avm2: Grant each event it's own, separate broadcast list.
This commit is contained in:
parent
8e8de09f63
commit
540a68fb68
|
@ -4,9 +4,11 @@ use crate::avm2::globals::SystemPrototypes;
|
||||||
use crate::avm2::method::Method;
|
use crate::avm2::method::Method;
|
||||||
use crate::avm2::object::EventObject;
|
use crate::avm2::object::EventObject;
|
||||||
use crate::avm2::script::{Script, TranslationUnit};
|
use crate::avm2::script::{Script, TranslationUnit};
|
||||||
|
use crate::avm2::string::AvmString;
|
||||||
use crate::context::UpdateContext;
|
use crate::context::UpdateContext;
|
||||||
use crate::tag_utils::SwfSlice;
|
use crate::tag_utils::SwfSlice;
|
||||||
use gc_arena::{Collect, MutationContext};
|
use gc_arena::{Collect, MutationContext};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use swf::avm2::read::Reader;
|
use swf::avm2::read::Reader;
|
||||||
|
|
||||||
|
@ -73,7 +75,7 @@ pub struct Avm2<'gc> {
|
||||||
///
|
///
|
||||||
/// TODO: These should be weak object pointers, but our current garbage
|
/// TODO: These should be weak object pointers, but our current garbage
|
||||||
/// collector does not support weak references.
|
/// collector does not support weak references.
|
||||||
broadcast_list: Vec<Object<'gc>>,
|
broadcast_list: HashMap<AvmString<'gc>, Vec<Object<'gc>>>,
|
||||||
|
|
||||||
#[cfg(feature = "avm_debug")]
|
#[cfg(feature = "avm_debug")]
|
||||||
pub debug_output: bool,
|
pub debug_output: bool,
|
||||||
|
@ -88,7 +90,7 @@ impl<'gc> Avm2<'gc> {
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
globals,
|
globals,
|
||||||
system_prototypes: None,
|
system_prototypes: None,
|
||||||
broadcast_list: Vec::new(),
|
broadcast_list: HashMap::new(),
|
||||||
|
|
||||||
#[cfg(feature = "avm_debug")]
|
#[cfg(feature = "avm_debug")]
|
||||||
debug_output: false,
|
debug_output: false,
|
||||||
|
@ -155,8 +157,15 @@ impl<'gc> Avm2<'gc> {
|
||||||
pub fn register_broadcast_listener(
|
pub fn register_broadcast_listener(
|
||||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
object: Object<'gc>,
|
object: Object<'gc>,
|
||||||
|
event_name: AvmString<'gc>,
|
||||||
) {
|
) {
|
||||||
context.avm2.broadcast_list.push(object);
|
let bucket = context.avm2.broadcast_list.entry(event_name).or_default();
|
||||||
|
|
||||||
|
if bucket.iter().any(|x| Object::ptr_eq(*x, object)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bucket.push(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dispatch an event on all objects in the current execution list.
|
/// Dispatch an event on all objects in the current execution list.
|
||||||
|
@ -170,10 +179,22 @@ impl<'gc> Avm2<'gc> {
|
||||||
event: Event<'gc>,
|
event: Event<'gc>,
|
||||||
on_class_proto: Object<'gc>,
|
on_class_proto: Object<'gc>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let el_length = context.avm2.broadcast_list.len();
|
let event_name = event.event_type();
|
||||||
|
let el_length = context
|
||||||
|
.avm2
|
||||||
|
.broadcast_list
|
||||||
|
.entry(event_name)
|
||||||
|
.or_default()
|
||||||
|
.len();
|
||||||
|
|
||||||
for i in 0..el_length {
|
for i in 0..el_length {
|
||||||
let object = context.avm2.broadcast_list.get(i).copied();
|
let object = context
|
||||||
|
.avm2
|
||||||
|
.broadcast_list
|
||||||
|
.get(&event_name)
|
||||||
|
.unwrap()
|
||||||
|
.get(i)
|
||||||
|
.copied();
|
||||||
|
|
||||||
if let Some(object) = object {
|
if let Some(object) = object {
|
||||||
if object.has_prototype_in_chain(on_class_proto, true)? {
|
if object.has_prototype_in_chain(on_class_proto, true)? {
|
||||||
|
|
|
@ -38,8 +38,6 @@ pub fn instance_init<'gc>(
|
||||||
dispatch_list.into(),
|
dispatch_list.into(),
|
||||||
activation,
|
activation,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Avm2::register_broadcast_listener(&mut activation.context, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
|
@ -85,6 +83,8 @@ pub fn add_event_listener<'gc>(
|
||||||
.as_dispatch_mut(activation.context.gc_context)
|
.as_dispatch_mut(activation.context.gc_context)
|
||||||
.ok_or_else(|| Error::from("Internal properties should have what I put in them"))?
|
.ok_or_else(|| Error::from("Internal properties should have what I put in them"))?
|
||||||
.add_event_listener(event_type, priority, listener, use_capture);
|
.add_event_listener(event_type, priority, listener, use_capture);
|
||||||
|
|
||||||
|
Avm2::register_broadcast_listener(&mut activation.context, this, event_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
|
|
|
@ -526,6 +526,7 @@ swf_tests! {
|
||||||
(as3_movieclip_displayevents, "avm2/movieclip_displayevents", 9),
|
(as3_movieclip_displayevents, "avm2/movieclip_displayevents", 9),
|
||||||
(as3_movieclip_displayevents_timeline, "avm2/movieclip_displayevents_timeline", 5),
|
(as3_movieclip_displayevents_timeline, "avm2/movieclip_displayevents_timeline", 5),
|
||||||
(as3_movieclip_displayevents_looping, "avm2/movieclip_displayevents_looping", 5),
|
(as3_movieclip_displayevents_looping, "avm2/movieclip_displayevents_looping", 5),
|
||||||
|
(as3_movieclip_displayevents_dblhandler, "avm2/movieclip_displayevents_dblhandler", 4),
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: These tests have some inaccuracies currently, so we use approx_eq to test that numeric values are close enough.
|
// TODO: These tests have some inaccuracies currently, so we use approx_eq to test that numeric values are close enough.
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
mc exitframe
|
||||||
|
root exitframe
|
||||||
|
root exitframe 2
|
||||||
|
root enterframe
|
||||||
|
root enterframe 2
|
||||||
|
mc enterframe
|
||||||
|
mc exitframe
|
||||||
|
root exitframe
|
||||||
|
root exitframe 2
|
||||||
|
root enterframe
|
||||||
|
root enterframe 2
|
||||||
|
mc enterframe
|
||||||
|
mc exitframe
|
||||||
|
root exitframe
|
||||||
|
root exitframe 2
|
||||||
|
root enterframe
|
||||||
|
root enterframe 2
|
||||||
|
mc enterframe
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue