Skip to content

Commit 9eca71f

Browse files
Toad06kjarosh
authored andcommitted
core: Handle the case where frame rate is set to 0 or NaN
1 parent e795e68 commit 9eca71f

File tree

14 files changed

+130
-7
lines changed

14 files changed

+130
-7
lines changed

core/src/avm2/globals/flash/display/stage.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,12 @@ pub fn get_frame_rate<'gc>(
218218
_this: Object<'gc>,
219219
_args: &[Value<'gc>],
220220
) -> Result<Value<'gc>, Error<'gc>> {
221-
Ok((*activation.context.frame_rate).into())
221+
let mut frame_rate = *activation.context.frame_rate;
222+
if frame_rate < 0.0 {
223+
// Uncommon frame rate from the SWF header.
224+
frame_rate = frame_rate.rem_euclid(256.0);
225+
}
226+
Ok(frame_rate.into())
222227
}
223228

224229
/// Implement `frameRate`'s setter
@@ -228,7 +233,7 @@ pub fn set_frame_rate<'gc>(
228233
args: &[Value<'gc>],
229234
) -> Result<Value<'gc>, Error<'gc>> {
230235
if !activation.context.forced_frame_rate {
231-
let new_frame_rate = args.get_f64(activation, 0)?;
236+
let new_frame_rate = args.get_f64(activation, 0)?.clamp(0.01, 1000.0);
232237
*activation.context.frame_rate = new_frame_rate;
233238
}
234239

core/src/player.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ impl Player {
475475
if self.recent_run_frame_timings.is_empty() {
476476
5
477477
} else {
478-
let frame_time = 1000.0 / self.frame_rate;
478+
let frame_time = self.frame_time(1000.0);
479479
let average_run_frame_time = self.recent_run_frame_timings.iter().sum::<f64>()
480480
/ self.recent_run_frame_timings.len() as f64;
481481
((frame_time / average_run_frame_time) as u32).clamp(1, MAX_FRAMES_PER_TICK)
@@ -489,11 +489,19 @@ impl Player {
489489
}
490490
}
491491

492+
fn frame_time(&self, time_unit: f64) -> f64 {
493+
let frame_rate = self.frame_rate;
494+
if frame_rate == 0.0 || frame_rate.is_nan() {
495+
0.0
496+
} else {
497+
time_unit / frame_rate
498+
}
499+
}
500+
492501
pub fn tick(&mut self, dt: f64) {
493502
if self.is_playing() {
494503
self.frame_accumulator += dt;
495-
let frame_rate = self.frame_rate;
496-
let frame_time = 1000.0 / frame_rate;
504+
let frame_time = self.frame_time(1000.0);
497505

498506
let max_frames_per_tick = self.max_frames_per_tick();
499507
let mut frame = 0;
@@ -556,7 +564,7 @@ impl Player {
556564
/// Returns the approximate duration of time until the next frame is due to run.
557565
/// This is only an approximation to be used for sleep durations.
558566
pub fn time_til_next_frame(&self) -> std::time::Duration {
559-
let frame_time = 1000.0 / self.frame_rate;
567+
let frame_time = self.frame_time(1000.0);
560568
let mut dt = if self.frame_accumulator <= 0.0 {
561569
frame_time
562570
} else if self.frame_accumulator >= frame_time {
@@ -1874,7 +1882,8 @@ impl Player {
18741882

18751883
#[instrument(level = "debug", skip_all)]
18761884
pub fn run_frame(&mut self) {
1877-
let frame_time = Duration::from_nanos((750_000_000.0 / self.frame_rate) as u64);
1885+
let frame_time = self.frame_time(750_000_000.0);
1886+
let frame_time = Duration::from_nanos(frame_time as u64);
18781887
let (mut execution_limit, may_execute_while_streaming) = match self.load_behavior {
18791888
LoadBehavior::Streaming => (
18801889
ExecutionLimit::with_max_ops_and_time(10000, frame_time),
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// stage.frameRate (SWF header = 30)
2+
30
3+
// stage.frameRate = NaN;
4+
NaN
5+
// Event.ENTER_FRAME
6+
// Event.ENTER_FRAME
7+
// Event.ENTER_FRAME
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Test made using JPEXS Free Flash Decompiler.
2+
// The frame rate in the SWF header is set to 30.
3+
4+
package
5+
{
6+
import flash.display.Sprite;
7+
import flash.events.Event;
8+
9+
public class Test extends Sprite
10+
{
11+
public function Test()
12+
{
13+
super();
14+
this.init();
15+
}
16+
17+
private function init() : void
18+
{
19+
var enterFrame = function()
20+
{
21+
trace("// Event.ENTER_FRAME");
22+
};
23+
addEventListener(Event.ENTER_FRAME, enterFrame);
24+
trace("// stage.frameRate (SWF header = 30)");
25+
trace(stage.frameRate);
26+
trace("// stage.frameRate = NaN;");
27+
stage.frameRate = NaN;
28+
trace(stage.frameRate);
29+
}
30+
}
31+
}
1 KB
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
num_frames = 4
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// stage.frameRate (SWF header = -43.75)
2+
212.25
3+
// stage.frameRate = -43.75;
4+
0.01
5+
// stage.frameRate = 212.25;
6+
212.25
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Test made using JPEXS Free Flash Decompiler.
2+
// The frame rate in the SWF header is set to -43.75.
3+
4+
package
5+
{
6+
import flash.display.Sprite;
7+
8+
public class Test extends Sprite
9+
{
10+
public function Test()
11+
{
12+
super();
13+
this.init();
14+
}
15+
16+
private function init() : void
17+
{
18+
trace("// stage.frameRate (SWF header = -43.75)");
19+
trace(stage.frameRate);
20+
trace("// stage.frameRate = -43.75;");
21+
stage.frameRate = -43.75;
22+
trace(stage.frameRate);
23+
trace("// stage.frameRate = 212.25;");
24+
stage.frameRate = 212.25;
25+
trace(stage.frameRate);
26+
}
27+
}
28+
}
889 Bytes
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
num_frames = 1

0 commit comments

Comments
 (0)