core: In AVM2, run removals before frame advance.
We still retain the queue system as events are fired at removal time, and those events can trigger more gotos. If such a goto happens, AS3 code will hit a clip still in the old state rather than an inconsistent one. I don't have test coverage for this exact scenario just yet.
This commit is contained in:
parent
d691543c4c
commit
7a09bbfaab
|
@ -1111,7 +1111,10 @@ impl<'gc> MovieClip<'gc> {
|
||||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
run_display_actions: bool,
|
run_display_actions: bool,
|
||||||
) {
|
) {
|
||||||
match self.determine_next_frame() {
|
let next_frame = self.determine_next_frame();
|
||||||
|
match next_frame {
|
||||||
|
//Removals happen before frame advance.
|
||||||
|
NextFrame::Next if context.is_action_script_3() => {}
|
||||||
NextFrame::Next => self.0.write(context.gc_context).current_frame += 1,
|
NextFrame::Next => self.0.write(context.gc_context).current_frame += 1,
|
||||||
NextFrame::First => return self.run_goto(context, 1, true),
|
NextFrame::First => return self.run_goto(context, 1, true),
|
||||||
NextFrame::Same => self.stop(context),
|
NextFrame::Same => self.stop(context),
|
||||||
|
@ -1169,7 +1172,24 @@ impl<'gc> MovieClip<'gc> {
|
||||||
};
|
};
|
||||||
let _ = tag_utils::decode_tags(&mut reader, tag_callback, TagCode::ShowFrame);
|
let _ = tag_utils::decode_tags(&mut reader, tag_callback, TagCode::ShowFrame);
|
||||||
|
|
||||||
|
let remove_actions = self.unqueue_tags_matching(context, |t| {
|
||||||
|
matches!(t.tag_type, QueuedTagAction::Remove(_))
|
||||||
|
});
|
||||||
|
|
||||||
|
for (_, tag) in remove_actions {
|
||||||
|
let mut reader = data.read_from(tag.tag_start);
|
||||||
|
let version = match tag.tag_type {
|
||||||
|
QueuedTagAction::Remove(v) => v,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = self.remove_object(context, &mut reader, version) {
|
||||||
|
log::error!("Error running queued tag: {:?}, got {}", tag.tag_type, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut write = self.0.write(context.gc_context);
|
let mut write = self.0.write(context.gc_context);
|
||||||
|
|
||||||
write.tag_stream_pos = reader.get_ref().as_ptr() as u64 - tag_stream_start;
|
write.tag_stream_pos = reader.get_ref().as_ptr() as u64 - tag_stream_start;
|
||||||
|
|
||||||
// Check if our audio track has finished playing.
|
// Check if our audio track has finished playing.
|
||||||
|
@ -1179,6 +1199,10 @@ impl<'gc> MovieClip<'gc> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if matches!(next_frame, NextFrame::Next) && context.is_action_script_3() {
|
||||||
|
write.current_frame += 1;
|
||||||
|
}
|
||||||
|
|
||||||
let frame_id = write.current_frame;
|
let frame_id = write.current_frame;
|
||||||
write.queued_script_frame = Some(frame_id);
|
write.queued_script_frame = Some(frame_id);
|
||||||
}
|
}
|
||||||
|
@ -1962,23 +1986,6 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
|
||||||
|
|
||||||
if is_playing {
|
if is_playing {
|
||||||
self.run_frame_internal(context, true);
|
self.run_frame_internal(context, true);
|
||||||
|
|
||||||
let data = self.0.read().static_data.swf.clone();
|
|
||||||
let remove_actions = self.unqueue_tags_matching(context, |t| {
|
|
||||||
matches!(t.tag_type, QueuedTagAction::Remove(_))
|
|
||||||
});
|
|
||||||
|
|
||||||
for (_, tag) in remove_actions {
|
|
||||||
let mut reader = data.read_from(tag.tag_start);
|
|
||||||
let version = match tag.tag_type {
|
|
||||||
QueuedTagAction::Remove(v) => v,
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(e) = self.remove_object(context, &mut reader, version) {
|
|
||||||
log::error!("Error running queued tag: {:?}, got {}", tag.tag_type, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue