diff --git a/core/src/avm2/globals/flash/utils/Timer.as b/core/src/avm2/globals/flash/utils/Timer.as index c53e78b16..c17b8b0ee 100644 --- a/core/src/avm2/globals/flash/utils/Timer.as +++ b/core/src/avm2/globals/flash/utils/Timer.as @@ -32,11 +32,12 @@ package flash.utils { this.checkDelay(delay); this._delay = value; if (this.running) { - this.stop(); - this.start(); + this.updateDelay(); } } + private native function updateDelay():void; + public function get repeatCount(): int { return this._repeatCount; } diff --git a/core/src/avm2/globals/flash/utils/timer.rs b/core/src/avm2/globals/flash/utils/timer.rs index 496af0f33..196d1ca95 100644 --- a/core/src/avm2/globals/flash/utils/timer.rs +++ b/core/src/avm2/globals/flash/utils/timer.rs @@ -81,3 +81,32 @@ pub fn start<'gc>( } Ok(Value::Undefined) } + +/// Implements `Timer.updateDelay` +pub fn update_delay<'gc>( + activation: &mut Activation<'_, 'gc>, + this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let id = this + .get_property( + &Multiname::new(activation.avm2().flash_utils_internal, "_timerId"), + activation, + ) + .unwrap() + .coerce_to_i32(activation)?; + + let delay = this + .get_property( + &Multiname::new(activation.avm2().flash_utils_internal, "_delay"), + activation, + ) + .unwrap() + .coerce_to_i32(activation)?; + + if id != -1 { + activation.context.timers.set_delay(id, delay); + } + + Ok(Value::Undefined) +} diff --git a/core/src/timer.rs b/core/src/timer.rs index f10f6c219..7fb5fff34 100644 --- a/core/src/timer.rs +++ b/core/src/timer.rs @@ -258,6 +258,29 @@ impl<'gc> Timers<'gc> { len < old_len } + /// Changes the delay of a timer. + pub fn set_delay(&mut self, id: i32, interval: i32) { + // SANITY: Set a minimum interval so we don't spam too much. + let interval = interval.max(Self::MIN_INTERVAL) as u64 * (Self::TIMER_SCALE as u64); + + // Due to the limitations of `BinaryHeap`, we have to do this in a slightly roundabout way. + let mut timer = None; + for t in self.timers.iter() { + if t.id == id { + timer = Some(t.clone()); + break; + } + } + + if let Some(mut timer) = timer { + self.remove(id); + timer.interval = interval; + self.timers.push(timer); + } else { + panic!("Changing delay of non-existent timer"); + } + } + fn peek(&self) -> Option<&Timer<'gc>> { self.timers.peek() } @@ -286,7 +309,7 @@ unsafe impl<'gc> Collect for Timers<'gc> { } /// A timer created via `setInterval`/`setTimeout`. /// Runs a callback when it ticks. -#[derive(Collect)] +#[derive(Clone, Collect)] #[collect(no_drop)] pub struct Timer<'gc> { /// The ID of the timer.