avm1: Fix `onLoadInit` event order

`onLoadInit` is queued after all `DoAction`s of the loaded clips.
That is, if clip1, clip2, clip3 are loaded in the same frame
(in this order), then actions will be executed as follows:

* `DoAction` of clip3
* `DoAction` of clip2
* `DoAction` of clip1
* `onLoadInit` of clip3
* `onLoadInit` of clip2
* `onLoadInit` of clip1

Previously, those were incorrectly executed as follows:

* `DoAction` of clip3
* `onLoadInit` of clip3
* `DoAction` of clip2
* `onLoadInit` of clip2
* `DoAction` of clip1
* `onLoadInit` of clip1
This commit is contained in:
relrelb 2022-01-14 21:11:00 +02:00 committed by Mike Welsh
parent 12f9bec194
commit 25722e7abe
3 changed files with 11 additions and 60 deletions

View File

@ -1772,10 +1772,7 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
fn run_frame(&self, context: &mut UpdateContext<'_, 'gc, '_>) {
// Run my load/enterFrame clip event.
let mc = self.0.write(context.gc_context);
let is_load_frame = !mc.initialized();
drop(mc);
let is_load_frame = !self.0.read().initialized();
if is_load_frame {
self.event_dispatch(context, ClipEvent::Load);
self.0.write(context.gc_context).set_initialized(true);
@ -1787,14 +1784,6 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
if self.playing() {
self.run_frame_internal(context, true);
}
if is_load_frame {
self.0.write(context.gc_context).run_clip_postevent(
(*self).into(),
context,
ClipEvent::Load,
);
}
}
fn run_frame_scripts(self, context: &mut UpdateContext<'_, 'gc, '_>) {
@ -2309,32 +2298,6 @@ impl<'gc> MovieClipData<'gc> {
Ok(())
}
/// Run clip actions that trigger after the clip's own actions.
///
/// Currently, this is purely limited to `MovieClipLoader`'s `onLoadInit`
/// event, delivered via the `LoadManager`. We need to be called here so
/// that external init code runs after the event.
///
/// TODO: If it turns out other `Load` events need to be delayed, perhaps
/// we should change which frame triggers a `Load` event, rather than
/// making sure our actions run after the clip's.
fn run_clip_postevent(
&self,
self_display_object: DisplayObject<'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
event: ClipEvent,
) {
// Finally, queue any loaders that may be waiting for this event.
if let ClipEvent::Load = event {
context.load_manager.movie_clip_on_load(
self_display_object,
//TODO: This should have an AVM2 onload path.
self.object.and_then(|o| o.as_avm1_object().ok()),
context.action_queue,
);
}
}
pub fn clip_event_handlers(&self) -> &[ClipEventHandler] {
&self.clip_event_handlers
}

View File

@ -156,16 +156,11 @@ impl<'gc> LoadManager<'gc> {
/// Indicates that a movie clip has initialized (ran its first frame).
///
/// Interested loaders will be invoked from here.
pub fn movie_clip_on_load(
&mut self,
loaded_clip: DisplayObject<'gc>,
clip_object: Option<Object<'gc>>,
queue: &mut ActionQueue<'gc>,
) {
pub fn movie_clip_on_load(&mut self, queue: &mut ActionQueue<'gc>) {
let mut invalidated_loaders = vec![];
for (index, loader) in self.0.iter_mut() {
if loader.movie_clip_loaded(loaded_clip, clip_object, queue) {
for (index, loader) in self.0.iter_mut().rev() {
if loader.movie_clip_loaded(queue) {
invalidated_loaders.push(index);
}
}
@ -657,12 +652,7 @@ impl<'gc> Loader<'gc> {
/// Returns `true` if the loader has completed and should be removed.
///
/// Used to fire listener events on clips and terminate completed loaders.
pub fn movie_clip_loaded(
&mut self,
loaded_clip: DisplayObject<'gc>,
clip_object: Option<Object<'gc>>,
queue: &mut ActionQueue<'gc>,
) -> bool {
fn movie_clip_loaded(&mut self, queue: &mut ActionQueue<'gc>) -> bool {
let (clip, broadcaster, loader_status) = match self {
Loader::Movie {
target_clip,
@ -673,10 +663,6 @@ impl<'gc> Loader<'gc> {
_ => return false,
};
if !DisplayObject::ptr_eq(loaded_clip, clip) {
return false;
}
match loader_status {
LoaderStatus::Pending => false,
LoaderStatus::Failed => true,
@ -687,10 +673,7 @@ impl<'gc> Loader<'gc> {
ActionType::Method {
object: broadcaster,
name: "broadcastMessage",
args: vec![
"onLoadInit".into(),
clip_object.map(|co| co.into()).unwrap_or(Value::Undefined),
],
args: vec!["onLoadInit".into(), clip.object()],
},
false,
);

View File

@ -1275,6 +1275,11 @@ impl Player {
clip.run_frame(context);
}
}
// Fire "onLoadInit" events.
context
.load_manager
.movie_clip_on_load(context.action_queue);
}
AvmType::Avm2 => {
stage.exit_frame(context);