Implement the MovieClip loading portion of `ActionGetURL2`.

This commit is contained in:
David Wendt 2019-11-12 20:53:04 -05:00
parent 5ed5876e9a
commit 8c9d290db7
2 changed files with 74 additions and 10 deletions

View File

@ -8,12 +8,14 @@ use gc_arena::{GcCell, MutationContext};
use rand::Rng;
use std::collections::HashMap;
use std::convert::TryInto;
use std::sync::Arc;
use url::form_urlencoded;
use swf::avm1::read::Reader;
use swf::avm1::types::{Action, Function};
use crate::tag_utils::SwfSlice;
use crate::display_object::DisplayObject;
use crate::tag_utils::{SwfMovie, SwfSlice};
#[cfg(test)]
#[macro_use]
@ -1665,14 +1667,14 @@ impl<'gc> Avm1<'gc> {
return fscommand::handle(fscommand, self, context);
}
if is_load_vars {
let clip_target: Option<DisplayObject<'gc>> = if is_target_sprite {
let start = self.target_clip_or_root(context);
self.resolve_target_display_object(context, start, target)?
} else {
Some(self.target_clip_or_root(context))
};
let clip_target: Option<DisplayObject<'gc>> = if is_target_sprite {
let start = self.target_clip_or_root(context);
self.resolve_target_display_object(context, start, target.clone())?
} else {
Some(self.target_clip_or_root(context))
};
if is_load_vars {
if let Some(clip_target) = clip_target {
let target_obj = clip_target
.as_movie_clip()
@ -1699,8 +1701,27 @@ impl<'gc> Avm1<'gc> {
return Ok(());
} else if is_target_sprite {
log::warn!("GetURL into target sprite is not yet implemented");
return Ok(()); //maybe error?
if let Some(clip_target) = clip_target {
let player = context.player.clone().unwrap().upgrade().unwrap();
let fetch = context.navigator.fetch(url);
let slot = self.forcibly_root_object(clip_target.object().as_object()?);
context.navigator.spawn_future(Box::pin(async move {
let data = fetch.await.unwrap();
let movie = Arc::new(SwfMovie::from_data(&data));
player.lock().unwrap().update(|avm, uc| {
let that = avm.unroot_object(slot);
that.as_display_object()
.unwrap()
.as_movie_clip()
.unwrap()
.replace_with_movie(uc.gc_context, movie);
})
}))
}
return Ok(());
} else {
let vars = match NavigationMethod::from_send_vars_method(swf_method) {
Some(method) => Some((method, self.locals_into_form_values(context))),

View File

@ -103,6 +103,21 @@ impl<'gc> MovieClip<'gc> {
)
}
/// Replace the current MovieClip with a completely new SwfMovie.
///
/// Playback will start at position zero, any existing streamed audio will
/// be terminated, and so on. Children and AVM data will be kept across the
/// load boundary.
pub fn replace_with_movie(
&mut self,
gc_context: MutationContext<'gc, '_>,
movie: Arc<SwfMovie>,
) {
self.0
.write(gc_context)
.replace_with_movie(gc_context, movie)
}
pub fn preload(
self,
context: &mut UpdateContext<'_, 'gc, '_>,
@ -406,6 +421,34 @@ unsafe impl<'gc> Collect for MovieClipData<'gc> {
}
impl<'gc> MovieClipData<'gc> {
/// Replace the current MovieClipData with a completely new SwfMovie.
///
/// Playback will start at position zero, any existing streamed audio will
/// be terminated, and so on. Children and AVM data will be kept across the
/// load boundary.
pub fn replace_with_movie(
&mut self,
gc_context: MutationContext<'gc, '_>,
movie: Arc<SwfMovie>,
) {
let total_frames = movie.header().num_frames;
self.static_data = Gc::allocate(
gc_context,
MovieClipStatic {
id: self.static_data.id, //TODO: This is WRONG; This is VERRRRY WRONG!
swf: movie.into(),
total_frames,
audio_stream_info: None,
frame_labels: HashMap::new(),
},
);
self.tag_stream_pos = 0;
self.flags = EnumSet::empty();
self.current_frame = 0;
self.audio_stream = None;
}
fn id(&self) -> CharacterId {
self.static_data.id
}