avm1: Don't create _levelN for unloadMovieNum(N)

This commit is contained in:
Nathan Adams 2023-06-09 15:40:03 +02:00
parent e8925832a1
commit 38a3f67000
4 changed files with 40 additions and 15 deletions

View File

@ -1196,15 +1196,15 @@ impl<'a, 'gc> Activation<'a, 'gc> {
if target.starts_with(WStr::from_units(b"_level")) && target.len() > 6 { if target.starts_with(WStr::from_units(b"_level")) && target.len() > 6 {
match target[6..].parse::<i32>() { match target[6..].parse::<i32>() {
Ok(level_id) => { Ok(level_id) => {
let level = self.resolve_level(level_id);
if url.is_empty() { if url.is_empty() {
let level = self.try_resolve_level(level_id);
// Blank URL on movie loads = unload! // Blank URL on movie loads = unload!
if let Some(mc) = level.as_movie_clip() { if let Some(mc) = level.and_then(|o| o.as_movie_clip()) {
mc.avm1_unload(&mut self.context); mc.avm1_unload(&mut self.context);
mc.replace_with_movie(&mut self.context, None, None) mc.replace_with_movie(&mut self.context, None, None)
} }
} else { } else {
let level = self.resolve_level(level_id);
let future = self.context.load_manager.load_movie_into_clip( let future = self.context.load_manager.load_movie_into_clip(
self.context.player.clone(), self.context.player.clone(),
level, level,
@ -1268,8 +1268,8 @@ impl<'a, 'gc> Activation<'a, 'gc> {
-1 -1
}; };
let clip_target: Option<DisplayObject<'gc>> = if level_target > -1 { let mut clip_target: Option<DisplayObject<'gc>> = if level_target > -1 {
Some(self.resolve_level(level_target)) self.try_resolve_level(level_target)
} else if action.is_load_vars() || action.is_target_sprite() { } else if action.is_load_vars() || action.is_target_sprite() {
if let Value::Object(target) = target_val { if let Value::Object(target) = target_val {
target.as_display_object() target.as_display_object()
@ -1323,14 +1323,19 @@ impl<'a, 'gc> Activation<'a, 'gc> {
} }
} else if action.is_target_sprite() { } else if action.is_target_sprite() {
// `loadMovie`, `unloadMovie` or `unloadMovieNum` call. // `loadMovie`, `unloadMovie` or `unloadMovieNum` call.
if let Some(clip_target) = clip_target {
if url.is_empty() { if url.is_empty() {
// Blank URL on movie loads = unload! // Blank URL on movie loads = unload!
if let Some(mc) = clip_target.as_movie_clip() { if let Some(mc) = clip_target.and_then(|o| o.as_movie_clip()) {
mc.avm1_unload(&mut self.context); mc.avm1_unload(&mut self.context);
mc.replace_with_movie(&mut self.context, None, None) mc.replace_with_movie(&mut self.context, None, None)
} }
} else { } else {
if clip_target.is_none() && level_target > -1 {
// Ensure the level exists
// [NA] TODO: This should actually create the level in the future when it's loaded
clip_target = Some(self.resolve_level(level_target));
}
if let Some(clip_target) = clip_target {
let request = self.locals_into_request( let request = self.locals_into_request(
url, url,
NavigationMethod::from_send_vars_method(action.send_vars_method()), NavigationMethod::from_send_vars_method(action.send_vars_method()),
@ -1348,6 +1353,11 @@ impl<'a, 'gc> Activation<'a, 'gc> {
return Ok(FrameControl::Continue); return Ok(FrameControl::Continue);
} else if level_target > -1 { } else if level_target > -1 {
// `loadMovieNum` call. // `loadMovieNum` call.
if clip_target.is_none() && level_target > -1 {
// Ensure the level exists
// [NA] TODO: This should actually create the level in the future when it's loaded
clip_target = Some(self.resolve_level(level_target));
}
if let Some(clip_target) = clip_target { if let Some(clip_target) = clip_target {
if url.is_empty() { if url.is_empty() {
// Blank URL on movie loads = unload! // Blank URL on movie loads = unload!
@ -2841,7 +2851,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
/// If the level does not exist, then it will be created and instantiated /// If the level does not exist, then it will be created and instantiated
/// with a script object. /// with a script object.
pub fn resolve_level(&mut self, level_id: i32) -> DisplayObject<'gc> { pub fn resolve_level(&mut self, level_id: i32) -> DisplayObject<'gc> {
if let Some(level) = self.context.stage.child_by_depth(level_id) { if let Some(level) = self.try_resolve_level(level_id) {
level level
} else { } else {
let level: DisplayObject<'_> = let level: DisplayObject<'_> =
@ -2858,6 +2868,11 @@ impl<'a, 'gc> Activation<'a, 'gc> {
} }
} }
/// Tries to resolve a level by ID. Returns None if it does not exist.
pub fn try_resolve_level(&mut self, level_id: i32) -> Option<DisplayObject<'gc>> {
self.context.stage.child_by_depth(level_id)
}
/// The current target clip of the executing code. /// The current target clip of the executing code.
/// Actions that affect `root` after an invalid `tellTarget` will use this. /// Actions that affect `root` after an invalid `tellTarget` will use this.
/// ///

View File

@ -1,3 +1,13 @@
// level1
undefined
// unloadMovieNum(1) (before it's loaded)
// level1
undefined
Loading movie Loading movie
Child movie loaded! Child movie loaded!
Unloading movie // level1 before unload
_level1
// unloadMovieNum(1)
// level1
_level1
Next frame