Store the movie associated with a given symbol being constructed.

This commit is contained in:
David Wendt 2021-04-09 20:32:04 -04:00 committed by Mike Welsh
parent 282508a281
commit 9b19cc1570
2 changed files with 46 additions and 10 deletions

View File

@ -599,7 +599,7 @@ impl<'gc> MovieClip<'gc> {
.context .context
.library .library
.avm2_constructor_registry_mut() .avm2_constructor_registry_mut()
.set_proto_symbol(proto, id), .set_proto_symbol(proto, movie.clone(), id),
Err(e) => log::warn!( Err(e) => log::warn!(
"Got AVM2 error {} when getting prototype of symbol class {}", "Got AVM2 error {} when getting prototype of symbol class {}",
e, e,

View File

@ -13,7 +13,7 @@ use gc_arena::{Collect, Gc, GcCell, MutationContext};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use swf::{CharacterId, TagCode}; use swf::{CharacterId, TagCode};
use weak_table::PtrWeakKeyHashMap; use weak_table::{traits::WeakElement, PtrWeakKeyHashMap, WeakValueHashMap};
/// Boxed error alias. /// Boxed error alias.
type Error = Box<dyn std::error::Error>; type Error = Box<dyn std::error::Error>;
@ -57,14 +57,42 @@ impl<'gc> Avm1ConstructorRegistry<'gc> {
} }
} }
#[derive(Clone)]
struct MovieSymbol(Arc<SwfMovie>, CharacterId);
#[derive(Clone)]
struct WeakMovieSymbol(Weak<SwfMovie>, CharacterId);
impl WeakElement for WeakMovieSymbol {
type Strong = MovieSymbol;
fn new(view: &Self::Strong) -> Self {
Self(Arc::downgrade(&view.0), view.1)
}
fn view(&self) -> Option<Self::Strong> {
if let Some(strong) = self.0.upgrade() {
Some(MovieSymbol(strong, self.1))
} else {
None
}
}
}
/// The mappings between prototypes and library characters defined by /// The mappings between prototypes and library characters defined by
/// `SymbolClass`. /// `SymbolClass`.
#[derive(Collect)]
#[collect(no_drop)]
pub struct Avm2ConstructorRegistry<'gc> { pub struct Avm2ConstructorRegistry<'gc> {
/// A list of AVM2 class prototypes and the character IDs they are expected /// A list of AVM2 class prototypes and the character IDs they are expected
/// to instantiate. /// to instantiate.
proto_map: HashMap<Avm2Object<'gc>, CharacterId>, proto_map: WeakValueHashMap<Avm2Object<'gc>, WeakMovieSymbol>,
}
unsafe impl Collect for Avm2ConstructorRegistry<'_> {
fn trace(&self, cc: gc_arena::CollectionContext) {
for (k, _) in self.proto_map.iter() {
k.trace(cc);
}
}
} }
impl Default for Avm2ConstructorRegistry<'_> { impl Default for Avm2ConstructorRegistry<'_> {
@ -76,7 +104,7 @@ impl Default for Avm2ConstructorRegistry<'_> {
impl<'gc> Avm2ConstructorRegistry<'gc> { impl<'gc> Avm2ConstructorRegistry<'gc> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
proto_map: HashMap::new(), proto_map: WeakValueHashMap::new(),
} }
} }
@ -84,13 +112,21 @@ impl<'gc> Avm2ConstructorRegistry<'gc> {
/// ///
/// A value of `None` indicates that this AVM2 class is not associated with /// A value of `None` indicates that this AVM2 class is not associated with
/// a library symbol. /// a library symbol.
pub fn proto_symbol(&self, proto: Avm2Object<'gc>) -> Option<CharacterId> { pub fn proto_symbol(&self, proto: Avm2Object<'gc>) -> Option<(Arc<SwfMovie>, CharacterId)> {
self.proto_map.get(&proto).copied() match self.proto_map.get(&proto) {
Some(MovieSymbol(movie, symbol)) => Some((movie, symbol)),
None => None,
}
} }
/// Associate an AVM2 prototype with a given library symbol. /// Associate an AVM2 prototype with a given library symbol.
pub fn set_proto_symbol(&mut self, proto: Avm2Object<'gc>, symbol: CharacterId) { pub fn set_proto_symbol(
self.proto_map.insert(proto, symbol); &mut self,
proto: Avm2Object<'gc>,
movie: Arc<SwfMovie>,
symbol: CharacterId,
) {
self.proto_map.insert(proto, MovieSymbol(movie, symbol));
} }
} }