avm1: Fix `loadVariablesNum` / `Action::GetUrl2`

This commit is contained in:
Toad06 2022-02-23 20:22:16 +01:00 committed by Mike Welsh
parent badb91c1db
commit 055e1d4dc1
1 changed files with 82 additions and 64 deletions

View File

@ -1190,29 +1190,59 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
fn action_get_url_2(&mut self, action: GetUrl2) -> Result<FrameControl<'gc>, Error<'gc>> { fn action_get_url_2(&mut self, action: GetUrl2) -> Result<FrameControl<'gc>, Error<'gc>> {
// TODO: Support `LoadVariablesFlag`, `LoadTargetFlag` // TODO: Support `LoadVariablesFlag`, `LoadTargetFlag`
// TODO: What happens if there's only one string? // TODO: What happens if there's only one string?
let target = self.context.avm1.pop(); let target_val = self.context.avm1.pop();
let target = target_val.coerce_to_string(self)?;
let url_val = self.context.avm1.pop(); let url_val = self.context.avm1.pop();
let url = url_val.coerce_to_string(self)?; let url = url_val.coerce_to_string(self)?;
if let Some(fscommand) = fscommand::parse(&url) { if let Some(fscommand) = fscommand::parse(&url) {
let fsargs = target.coerce_to_string(self)?; // `target` = fscommand arguments!
fscommand::handle(fscommand, &fsargs, self)?; fscommand::handle(fscommand, &target, self)?;
return Ok(FrameControl::Continue); return Ok(FrameControl::Continue);
} }
let window_target = target.coerce_to_string(self)?; // TODO: Use `StageObject::get_level_by_path`.
let clip_target: Option<DisplayObject<'gc>> = if action.is_target_sprite() { let level_target = if target.starts_with(WStr::from_units(b"_level")) && target.len() >= 6 {
if let Value::Object(target) = target { match target[6..].parse::<f64>() {
Ok(level_id) => level_id as i32,
Err(_) => {
if target.len() == 6 {
0
} else {
-1
}
}
}
} else {
-1
};
let clip_target: Option<DisplayObject<'gc>> = if level_target > -1 {
Some(self.resolve_level(level_target))
} else if action.is_load_vars() || action.is_target_sprite() {
if let Value::Object(target) = target_val {
target.as_display_object() target.as_display_object()
} else { } else {
let start = self.target_clip_or_root(); let start = self.target_clip_or_root();
self.resolve_target_display_object(start, target, true)? self.resolve_target_display_object(start, target_val, true)?
} }
} else { } else {
Some(self.target_clip_or_root()) None
}; };
if action.is_load_vars() { if action.is_load_vars() {
// `loadVariables` or `loadVariablesNum` call.
// Depending on the situation, it will open a link in the browser instead.
let mut is_load_vars = true;
if !(action.is_target_sprite() || level_target > -1) {
is_load_vars = false;
if matches!(target_val, Value::Object(_)) {
if let Some(clip) = clip_target {
is_load_vars = DisplayObject::ptr_eq(clip, self.base_clip().avm1_root());
}
}
}
if is_load_vars {
if let Some(clip_target) = clip_target { if let Some(clip_target) = clip_target {
let target_obj = clip_target let target_obj = clip_target
.as_movie_clip() .as_movie_clip()
@ -1231,9 +1261,10 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
); );
self.context.navigator.spawn_future(future); self.context.navigator.spawn_future(future);
} }
return Ok(FrameControl::Continue); return Ok(FrameControl::Continue);
}
} else if action.is_target_sprite() { } else if action.is_target_sprite() {
// `loadMovie`, `unloadMovie` or `unloadMovieNum` call.
if let Some(clip_target) = clip_target { if let Some(clip_target) = clip_target {
let (url, opts) = self.locals_into_request_options( let (url, opts) = self.locals_into_request_options(
&url, &url,
@ -1258,17 +1289,12 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
} }
} }
return Ok(FrameControl::Continue); return Ok(FrameControl::Continue);
} else if window_target.starts_with(WStr::from_units(b"_level")) && window_target.len() > 6 } else if level_target > -1 {
{ // `loadMovieNum` call.
// TODO: Use `StageObject::get_level_by_path`. if let Some(clip_target) = clip_target {
// target of `_level#` indicates a `loadMovieNum` call.
match window_target[6..].parse::<i32>() {
Ok(level_id) => {
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().unwrap(), self.context.player.clone().unwrap(),
level, clip_target,
&url.to_utf8_lossy(), &url.to_utf8_lossy(),
RequestOptions::get(), RequestOptions::get(),
None, None,
@ -1276,27 +1302,19 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
); );
self.context.navigator.spawn_future(future); self.context.navigator.spawn_future(future);
} }
Err(e) => avm_warn!( return Ok(FrameControl::Continue);
self,
"Couldn't parse level id {} for action_get_url_2: {}",
url,
e
),
} }
return Ok(FrameControl::Continue); // `getURL` call.
} else {
let vars = match NavigationMethod::from_send_vars_method(action.send_vars_method()) { let vars = match NavigationMethod::from_send_vars_method(action.send_vars_method()) {
Some(method) => Some((method, self.locals_into_form_values())), Some(method) => Some((method, self.locals_into_form_values())),
None => None, None => None,
}; };
self.context.navigator.navigate_to_url( self.context
url.to_string(), .navigator
Some(window_target.to_string()), .navigate_to_url(url.to_string(), Some(target.to_string()), vars);
vars,
);
}
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }