From 8cbd527e4cc9673f4bde333b0954b3197d3c25b9 Mon Sep 17 00:00:00 2001 From: moulins Date: Sun, 6 Nov 2022 06:39:11 +0100 Subject: [PATCH] avm1: Small cleanups in ActionQueue (#8486) - Use a fixed-size array instead of a Vec for the queues - Remove unwanted plurals in methods and types names --- core/src/backend/audio.rs | 4 ++-- core/src/context.rs | 31 ++++++++++---------------- core/src/display_object/avm1_button.rs | 4 ++-- core/src/display_object/movie_clip.rs | 10 ++++----- core/src/loader.rs | 4 ++-- core/src/player.rs | 22 +++++++++--------- 6 files changed, 34 insertions(+), 41 deletions(-) diff --git a/core/src/backend/audio.rs b/core/src/backend/audio.rs index ddb658396..830f9dd82 100644 --- a/core/src/backend/audio.rs +++ b/core/src/backend/audio.rs @@ -324,7 +324,7 @@ impl<'gc> AudioManager<'gc> { object.set_position(gc_context, duration.round() as u32); // Fire soundComplete event. - action_queue.queue_actions( + action_queue.queue_action( root, crate::context::ActionType::Method { object: object.into(), @@ -340,7 +340,7 @@ impl<'gc> AudioManager<'gc> { //TODO: AVM2 events are usually not queued, but we can't //hold the update context in the audio manager yet. - action_queue.queue_actions( + action_queue.queue_action( root, crate::context::ActionType::Event2 { event_type: "soundComplete", diff --git a/core/src/context.rs b/core/src/context.rs index 1522c0301..c44a9e3b6 100644 --- a/core/src/context.rs +++ b/core/src/context.rs @@ -355,7 +355,7 @@ impl<'a, 'gc, 'gc_context> UpdateContext<'a, 'gc, 'gc_context> { /// A queued ActionScript call. #[derive(Collect)] #[collect(no_drop)] -pub struct QueuedActions<'gc> { +pub struct QueuedAction<'gc> { /// The movie clip this ActionScript is running on. pub clip: DisplayObject<'gc>, @@ -371,7 +371,7 @@ pub struct QueuedActions<'gc> { #[collect(no_drop)] pub struct ActionQueue<'gc> { /// Each priority is kept in a separate bucket. - action_queue: Vec>>, + action_queue: [VecDeque>; ActionQueue::NUM_PRIORITIES], } impl<'gc> ActionQueue<'gc> { @@ -380,24 +380,20 @@ impl<'gc> ActionQueue<'gc> { /// Crates a new `ActionQueue` with an empty queue. pub fn new() -> Self { - let mut action_queue = Vec::with_capacity(Self::NUM_PRIORITIES); - for _ in 0..Self::NUM_PRIORITIES { - action_queue.push(VecDeque::with_capacity(Self::DEFAULT_CAPACITY)) - } + let action_queue = std::array::from_fn(|_| VecDeque::with_capacity(Self::DEFAULT_CAPACITY)); Self { action_queue } } - /// Queues ActionScript to run for the given movie clip. - /// `actions` is the slice of ActionScript bytecode to run. - /// The actions will be skipped if the clip is removed before the actions run. - pub fn queue_actions( + /// Queues an action to run for the given movie clip. + /// The action will be skipped if the clip is removed before the action runs. + pub fn queue_action( &mut self, clip: DisplayObject<'gc>, action_type: ActionType<'gc>, is_unload: bool, ) { let priority = action_type.priority(); - let action = QueuedActions { + let action = QueuedAction { clip, action_type, is_unload, @@ -409,14 +405,11 @@ impl<'gc> ActionQueue<'gc> { } /// Sorts and drains the actions from the queue. - pub fn pop_action(&mut self) -> Option> { - for queue in self.action_queue.iter_mut().rev() { - let action = queue.pop_front(); - if action.is_some() { - return action; - } - } - None + pub fn pop_action(&mut self) -> Option> { + self.action_queue + .iter_mut() + .rev() + .find_map(VecDeque::pop_front) } } diff --git a/core/src/display_object/avm1_button.rs b/core/src/display_object/avm1_button.rs index a72c9fd6d..598d72bcd 100644 --- a/core/src/display_object/avm1_button.rs +++ b/core/src/display_object/avm1_button.rs @@ -493,7 +493,7 @@ impl<'gc> TInteractiveObject<'gc> for Avm1Button<'gc> { // (e.g., clip.onRelease = foo). if context.swf.version() >= 6 { if let Some(name) = event.method_name() { - context.action_queue.queue_actions( + context.action_queue.queue_action( self_display_object, ActionType::Method { object: write.object.unwrap(), @@ -579,7 +579,7 @@ impl<'gc> Avm1ButtonData<'gc> { { // Note that AVM1 buttons run actions relative to their parent, not themselves. handled = ClipEventResult::Handled; - context.action_queue.queue_actions( + context.action_queue.queue_action( parent, ActionType::Normal { bytecode: action.action_data.clone(), diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index b90367e29..82e4ce726 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -2002,7 +2002,7 @@ impl<'gc> MovieClip<'gc> { .iter() { if event_handler.events.contains(ClipEventFlag::INITIALIZE) { - context.action_queue.queue_actions( + context.action_queue.queue_action( self.into(), ActionType::Initialize { bytecode: event_handler.action_data.clone(), @@ -2015,7 +2015,7 @@ impl<'gc> MovieClip<'gc> { } } - context.action_queue.queue_actions( + context.action_queue.queue_action( self.into(), ActionType::Construct { constructor: avm1_constructor, @@ -2719,7 +2719,7 @@ impl<'gc> TInteractiveObject<'gc> for MovieClip<'gc> { } } - context.action_queue.queue_actions( + context.action_queue.queue_action( self.into(), ActionType::Normal { bytecode: event_handler.action_data.clone(), @@ -2735,7 +2735,7 @@ impl<'gc> TInteractiveObject<'gc> for MovieClip<'gc> { if let Some(name) = event.method_name() { // Keyboard events don't fire their methods unless the MovieClip has focus (#2120). if !event.is_key_event() || read.has_focus { - context.action_queue.queue_actions( + context.action_queue.queue_action( self.into(), ActionType::Method { object, @@ -3650,7 +3650,7 @@ impl<'gc, 'a> MovieClip<'gc> { .swf .resize_to_reader(reader, tag_len); if !slice.is_empty() { - context.action_queue.queue_actions( + context.action_queue.queue_action( self.into(), ActionType::Normal { bytecode: slice }, false, diff --git a/core/src/loader.rs b/core/src/loader.rs index 3efb5d66b..eeed7f292 100644 --- a/core/src/loader.rs +++ b/core/src/loader.rs @@ -876,7 +876,7 @@ impl<'gc> Loader<'gc> { // Fire the onData method and event. if let Some(display_object) = that.as_display_object() { if let Some(movie_clip) = display_object.as_movie_clip() { - activation.context.action_queue.queue_actions( + activation.context.action_queue.queue_action( movie_clip.into(), ActionType::Method { object: that, @@ -1646,7 +1646,7 @@ impl<'gc> Loader<'gc> { LoaderStatus::Succeeded => { // AVM2 is handled separately if let Some(MovieLoaderEventHandler::Avm1Broadcast(broadcaster)) = event_handler { - queue.queue_actions( + queue.queue_action( clip, ActionType::Method { object: broadcaster, diff --git a/core/src/player.rs b/core/src/player.rs index c0ce59ee6..5632aa91a 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -1019,7 +1019,7 @@ impl Player { // Fire event listener on appropriate object if let Some((listener_type, event_name, args)) = listener { - context.action_queue.queue_actions( + context.action_queue.queue_action( context.stage.root_clip(), ActionType::NotifyListeners { listener: listener_type, @@ -1514,16 +1514,16 @@ impl Player { pub fn run_actions<'gc>(context: &mut UpdateContext<'_, 'gc, '_>) { // Note that actions can queue further actions, so a while loop is necessary here. - while let Some(actions) = context.action_queue.pop_action() { + while let Some(action) = context.action_queue.pop_action() { // We don't run frame actions if the clip was removed after it queued the action. - if !actions.is_unload && actions.clip.removed() { + if !action.is_unload && action.clip.removed() { continue; } - match actions.action_type { + match action.action_type { // DoAction/clip event code. ActionType::Normal { bytecode } | ActionType::Initialize { bytecode } => { - Avm1::run_stack_frame_for_action(actions.clip, "[Frame]", bytecode, context); + Avm1::run_stack_frame_for_action(action.clip, "[Frame]", bytecode, context); } // Change the prototype of a MovieClip and run constructor events. ActionType::Construct { @@ -1536,10 +1536,10 @@ impl Player { context.reborrow(), ActivationIdentifier::root("[Construct]"), globals, - actions.clip, + action.clip, ); if let Ok(prototype) = constructor.get("prototype", &mut activation) { - if let Value::Object(object) = actions.clip.object() { + if let Value::Object(object) = action.clip.object() { object.define_value( activation.context.gc_context, "__proto__", @@ -1549,7 +1549,7 @@ impl Player { for event in events { let _ = activation.run_child_frame_for_action( "[Actions]", - actions.clip, + action.clip, event, ); } @@ -1565,7 +1565,7 @@ impl Player { } => { for event in events { Avm1::run_stack_frame_for_action( - actions.clip, + action.clip, "[Construct]", event, context, @@ -1575,7 +1575,7 @@ impl Player { // Event handler method call (e.g. onEnterFrame). ActionType::Method { object, name, args } => { Avm1::run_stack_frame_for_method( - actions.clip, + action.clip, object, context, name.into(), @@ -1592,7 +1592,7 @@ impl Player { // A native function ends up resolving immediately, // so this doesn't require any further execution. Avm1::notify_system_listeners( - actions.clip, + action.clip, context, listener.into(), method.into(),