93 lines
4.1 KiB
Diff
93 lines
4.1 KiB
Diff
# UNDF: UNDF-2026-000001156
|
|
--- a/core/src/display_object/movie_clip.rs
|
|
+++ b/core/src/display_object/movie_clip.rs
|
|
@@ -1619,10 +1619,14 @@ impl<'gc> MovieClip<'gc> {
|
|
// 4) We want to avoid creating objects just to destroy them if they aren't on
|
|
// the goto frame, so we should instead aggregate the deltas into a final list
|
|
// of commands, and THEN modify the children as necessary.
|
|
-
|
|
- // This map will maintain a map of depth -> placement commands.
|
|
- // TODO: Move this to UpdateContext to avoid allocations.
|
|
- let mut goto_commands: Vec<GotoPlaceObject<'_>> = vec![];
|
|
+
|
|
+ // This map will maintain a map of depth -> placement commands.
|
|
+ // TODO: Move this to UpdateContext to avoid allocations.
|
|
+ let mut goto_commands: Vec<GotoPlaceObject<'_>> = vec![];
|
|
+ // O(1) depth lookup index: depth -> index in goto_commands Vec.
|
|
+ // Previously each goto_place_object/goto_remove_object call did
|
|
+ // iter().position() O(D) per SWF tag; a gotoAndPlay spanning F frames
|
|
+ // with D display objects per frame costs O(F*D^2). HashMap brings it to O(F*D).
|
|
+ let mut goto_depth_index: std::collections::HashMap<swf::Depth, usize> =
|
|
+ std::collections::HashMap::new();
|
|
|
|
@@ -1688,8 +1692,12 @@ impl<'gc> MovieClip<'gc> {
|
|
Action::Place(version) => {
|
|
index += 1;
|
|
self.0.goto_place_object(
|
|
+ &mut goto_depth_index,
|
|
reader,
|
|
version,
|
|
&mut goto_commands,
|
|
is_rewind,
|
|
index,
|
|
)
|
|
}
|
|
Action::Remove(version) => self.goto_remove_object(
|
|
+ &mut goto_depth_index,
|
|
reader,
|
|
version,
|
|
context,
|
|
@@ -2143,6 +2151,7 @@ impl<'gc> MovieClip<'gc> {
|
|
fn goto_remove_object<'a>(
|
|
mut self,
|
|
reader: &mut SwfStream<'a>,
|
|
version: u8,
|
|
context: &mut UpdateContext<'gc>,
|
|
+ goto_depth_index: &mut std::collections::HashMap<swf::Depth, usize>,
|
|
goto_commands: &mut Vec<GotoPlaceObject<'a>>,
|
|
is_rewind: bool,
|
|
from_frame: FrameNumber,
|
|
@@ -2158,8 +2167,14 @@ impl<'gc> MovieClip<'gc> {
|
|
}?;
|
|
let depth: Depth = remove_object.depth.into();
|
|
- if let Some(i) = goto_commands.iter().position(|o| o.depth() == depth) {
|
|
- goto_commands.swap_remove(i);
|
|
+ if let Some(&i) = goto_depth_index.get(&depth) {
|
|
+ let last_depth = goto_commands.last().map(|o| o.depth());
|
|
+ goto_commands.swap_remove(i);
|
|
+ goto_depth_index.remove(&depth);
|
|
+ // swap_remove moves the last element to position i; update its index entry.
|
|
+ if let Some(d) = last_depth {
|
|
+ if d != depth {
|
|
+ goto_depth_index.insert(d, i);
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
@@ -3301,6 +3316,7 @@ impl<'gc> MovieClip<'gc> {
|
|
fn goto_place_object<'a>(
|
|
&self,
|
|
reader: &mut SwfStream<'a>,
|
|
version: u8,
|
|
+ goto_depth_index: &mut std::collections::HashMap<swf::Depth, usize>,
|
|
goto_commands: &mut Vec<GotoPlaceObject<'a>>,
|
|
is_rewind: bool,
|
|
index: usize,
|
|
@@ -3325,10 +3341,15 @@ impl<'gc> MovieClip<'gc> {
|
|
let depth: Depth = place_object.depth.into();
|
|
let mut goto_place = GotoPlaceObject::new(
|
|
self.current_frame(),
|
|
place_object,
|
|
is_rewind,
|
|
index,
|
|
tag_start,
|
|
version,
|
|
);
|
|
- if let Some(i) = goto_commands.iter().position(|o| o.depth() == depth) {
|
|
- goto_commands[i].merge(&mut goto_place);
|
|
+ if let Some(&i) = goto_depth_index.get(&depth) {
|
|
+ goto_commands[i].merge(&mut goto_place);
|
|
} else {
|
|
+ goto_depth_index.insert(depth, goto_commands.len());
|
|
goto_commands.push(goto_place);
|
|
}
|