core: At the end of a goto, fix tag stream desyncs caused by not hitting the target frame.

If we try to go to a frame that doesn't exist, or hasn't been loaded yet, we will stop on the last available frame, but skip any tags that would have run there. This is technically a desync, but it hasn't caused any problems so far as any further timeline interaction would trigger a rewind (which isn't affected by desyncs).

Of course, now that we're actually testing the tag stream position it *does* cause problems. We actually have to fix up the position to be correct even though it will never be used (hopefully). It may be prudent to do this outside of the `timeline_debug` feature as well in the future.
This commit is contained in:
David Wendt 2022-07-02 01:55:52 -04:00 committed by Mike Welsh
parent 30b1d4af2a
commit fe828d7c24
1 changed files with 27 additions and 12 deletions

View File

@ -1264,18 +1264,33 @@ impl<'gc> MovieClip<'gc> {
fn assert_expected_tag_end(self) {} fn assert_expected_tag_end(self) {}
#[cfg(feature = "timeline_debug")] #[cfg(feature = "timeline_debug")]
fn assert_expected_tag_end(self) { fn assert_expected_tag_end(self, context: &mut UpdateContext<'_, 'gc, '_>, hit_target_frame: bool) {
let read = self.0.read(); // Gotos that do *not* hit their target frame will not update their tag
// stream position, as they do not run the final frame's tags, and thus
// cannot derive the end position of the clip anyway. This is not
// observable to user code as any further timeline interaction would
// trigger a rewind, so we ignore it here for now.
if hit_target_frame {
let read = self.0.read();
assert_eq!( assert_eq!(
Some(read.tag_stream_pos), Some(read.tag_stream_pos),
read.tag_frame_boundaries read.tag_frame_boundaries
.get(&read.current_frame) .get(&read.current_frame)
.map(|(_start, end)| *end), .map(|(_start, end)| *end),
"[{}] Gotos must end at the correct tag position for frame {}", "[{}] Gotos must end at the correct tag position for frame {}",
read.base.base.name, read.base.base.name,
read.current_frame read.current_frame
); );
} else {
// Of course, the target frame desync absolutely will break our
// other asserts, so fix them up here.
let mut write = self.0.write(context.gc_context);
if let Some((_, end)) = write.tag_frame_boundaries.get(&write.current_frame).cloned() {
write.tag_stream_pos = end;
}
}
} }
pub fn run_goto( pub fn run_goto(
@ -1479,7 +1494,7 @@ impl<'gc> MovieClip<'gc> {
self.exit_frame(context); self.exit_frame(context);
} }
self.assert_expected_tag_end(); self.assert_expected_tag_end(context, hit_target_frame);
} }
fn construct_as_avm1_object( fn construct_as_avm1_object(