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:
parent
12f9bec194
commit
25722e7abe
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue