Propagate the RNG to the action context. This lets random work.

This commit is contained in:
David Wendt 2019-09-01 21:03:50 -06:00 committed by Mike Welsh
parent 26c928b68f
commit 359d3e4780
4 changed files with 35 additions and 14 deletions

View File

@ -21,6 +21,7 @@ pub struct ActionContext<'a, 'gc, 'gc_context> {
pub root: DisplayNode<'gc>, pub root: DisplayNode<'gc>,
pub start_clip: DisplayNode<'gc>, pub start_clip: DisplayNode<'gc>,
pub active_clip: DisplayNode<'gc>, pub active_clip: DisplayNode<'gc>,
pub rng: &'a mut SmallRng,
pub audio: &'a mut dyn crate::backend::audio::AudioBackend, pub audio: &'a mut dyn crate::backend::audio::AudioBackend,
pub navigator: &'a mut dyn crate::backend::navigator::NavigatorBackend pub navigator: &'a mut dyn crate::backend::navigator::NavigatorBackend
} }
@ -28,7 +29,6 @@ pub struct ActionContext<'a, 'gc, 'gc_context> {
pub struct Avm1<'gc> { pub struct Avm1<'gc> {
swf_version: u8, swf_version: u8,
stack: Vec<Value<'gc>>, stack: Vec<Value<'gc>>,
rng: SmallRng,
constant_pool: Vec<String>, constant_pool: Vec<String>,
locals: HashMap<String, Value<'gc>>, locals: HashMap<String, Value<'gc>>,
globals: GcCell<'gc, Object<'gc>>, globals: GcCell<'gc, Object<'gc>>,
@ -50,7 +50,6 @@ impl<'gc> Avm1<'gc> {
Self { Self {
swf_version, swf_version,
stack: vec![], stack: vec![],
rng: SmallRng::from_seed([0u8; 16]), // TODO(Herschel): Get a proper seed on all platforms.
constant_pool: vec![], constant_pool: vec![],
locals: HashMap::new(), locals: HashMap::new(),
globals: GcCell::allocate(gc_context, create_globals(gc_context)), globals: GcCell::allocate(gc_context, create_globals(gc_context)),
@ -912,9 +911,9 @@ impl<'gc> Avm1<'gc> {
Ok(()) Ok(())
} }
fn action_random_number(&mut self, _context: &mut ActionContext) -> Result<(), Error> { fn action_random_number(&mut self, context: &mut ActionContext) -> Result<(), Error> {
let max = self.pop()?.as_f64()? as u32; let max = self.pop()?.as_f64()? as u32;
let val = self.rng.gen_range(0, max); let val = context.rng.gen_range(0, max);
self.push(Value::Number(val.into())); self.push(Value::Number(val.into()));
Ok(()) Ok(())
} }

View File

@ -1,5 +1,6 @@
use crate::avm1::{Object, Value, ActionContext}; use crate::avm1::{Object, Value, ActionContext};
use gc_arena::{MutationContext, GcCell}; use gc_arena::{MutationContext, GcCell};
use rand::Rng;
mod math; mod math;
@ -27,11 +28,14 @@ pub fn getURL<'a, 'gc>(
} }
pub fn random<'gc>( pub fn random<'gc>(
_action_context: &mut ActionContext<'_, 'gc, '_>, action_context: &mut ActionContext<'_, 'gc, '_>,
_this: GcCell<'gc, Object<'gc>>, _this: GcCell<'gc, Object<'gc>>,
args: &[Value<'gc>], args: &[Value<'gc>],
) -> Value<'gc> { ) -> Value<'gc> {
Value::Number(4.0) //chosen by fair dice roll. guaranteed to be random. match args.get(0) {
Some(Value::Number(max)) => Value::Number(action_context.rng.gen_range(0.0f64, max).floor()),
_ => Value::Undefined //TODO: Shouldn't this be an error condition?
}
} }
pub fn create_globals<'gc>(gc_context: MutationContext<'gc, '_>) -> Object<'gc> { pub fn create_globals<'gc>(gc_context: MutationContext<'gc, '_>) -> Object<'gc> {

View File

@ -1,6 +1,7 @@
use crate::avm1::{ActionContext, Object, Value}; use crate::avm1::{ActionContext, Object, Value};
use gc_arena::{GcCell, MutationContext}; use gc_arena::{GcCell, MutationContext};
use std::f64::NAN; use std::f64::NAN;
use rand::Rng;
macro_rules! wrap_std { macro_rules! wrap_std {
( $object: ident, $gc_context: ident, $($name:expr => $std:path),* ) => {{ ( $object: ident, $gc_context: ident, $($name:expr => $std:path),* ) => {{
@ -36,11 +37,11 @@ fn atan2<'gc>(
} }
pub fn random<'gc>( pub fn random<'gc>(
_action_context: &mut ActionContext<'_, 'gc, '_>, action_context: &mut ActionContext<'_, 'gc, '_>,
_this: GcCell<'gc, Object<'gc>>, _this: GcCell<'gc, Object<'gc>>,
_args: &[Value<'gc>], _args: &[Value<'gc>],
) -> Value<'gc> { ) -> Value<'gc> {
Value::Number(0.4) //chosen by fair dice roll. guaranteed to be random. Value::Number(action_context.rng.gen_range(0.0f64, 1.0f64))
} }
pub fn create<'gc>(gc_context: MutationContext<'gc, '_>) -> GcCell<'gc, Object<'gc>> { pub fn create<'gc>(gc_context: MutationContext<'gc, '_>) -> GcCell<'gc, Object<'gc>> {
@ -87,6 +88,7 @@ mod tests {
use crate::display_object::DisplayObject; use crate::display_object::DisplayObject;
use crate::movie_clip::MovieClip; use crate::movie_clip::MovieClip;
use gc_arena::rootless_arena; use gc_arena::rootless_arena;
use rand::{rngs::SmallRng, SeedableRng};
macro_rules! test_std { macro_rules! test_std {
( $test: ident, $name: expr, $($args: expr => $out: expr),* ) => { ( $test: ident, $name: expr, $($args: expr => $out: expr),* ) => {
@ -119,6 +121,7 @@ mod tests {
root, root,
start_clip: root, start_clip: root,
active_clip: root, active_clip: root,
rng: &mut SmallRng::from_seed([0u8; 16]),
audio: &mut NullAudioBackend::new(), audio: &mut NullAudioBackend::new(),
navigator: &mut NullNavigatorBackend::new() navigator: &mut NullNavigatorBackend::new()
}; };

View File

@ -5,6 +5,7 @@ use crate::library::Library;
use crate::movie_clip::MovieClip; use crate::movie_clip::MovieClip;
use crate::prelude::*; use crate::prelude::*;
use crate::transform::TransformStack; use crate::transform::TransformStack;
use rand::{rngs::SmallRng, SeedableRng};
use gc_arena::{make_arena, ArenaParameters, Collect, GcCell, MutationContext}; use gc_arena::{make_arena, ArenaParameters, Collect, GcCell, MutationContext};
use log::info; use log::info;
use std::sync::Arc; use std::sync::Arc;
@ -33,6 +34,8 @@ pub struct Player<Audio: AudioBackend, Renderer: RenderBackend, Navigator: Navig
view_matrix: Matrix, view_matrix: Matrix,
inverse_view_matrix: Matrix, inverse_view_matrix: Matrix,
rng: SmallRng,
gc_arena: GcArena, gc_arena: GcArena,
background_color: Color, background_color: Color,
@ -88,6 +91,8 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
view_matrix: Default::default(), view_matrix: Default::default(),
inverse_view_matrix: Default::default(), inverse_view_matrix: Default::default(),
rng: SmallRng::from_seed([0u8; 16]), // TODO(Herschel): Get a proper seed on all platforms.
gc_arena: GcArena::new(ArenaParameters::default(), |gc_context| GcRoot { gc_arena: GcArena::new(ArenaParameters::default(), |gc_context| GcRoot {
library: GcCell::allocate(gc_context, Library::new()), library: GcCell::allocate(gc_context, Library::new()),
root: GcCell::allocate( root: GcCell::allocate(
@ -205,7 +210,7 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
} }
} }
let (global_time, swf_data, swf_version, background_color, renderer, audio, navigator, is_mouse_down) = ( let (global_time, swf_data, swf_version, background_color, renderer, audio, navigator, rng, is_mouse_down) = (
self.global_time, self.global_time,
&mut self.swf_data, &mut self.swf_data,
self.swf_version, self.swf_version,
@ -213,6 +218,7 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
&mut self.renderer, &mut self.renderer,
&mut self.audio, &mut self.audio,
&mut self.navigator, &mut self.navigator,
&mut self.rng,
&mut self.is_mouse_down, &mut self.is_mouse_down,
); );
@ -224,6 +230,7 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
library: gc_root.library.write(gc_context), library: gc_root.library.write(gc_context),
background_color, background_color,
avm: gc_root.avm.write(gc_context), avm: gc_root.avm.write(gc_context),
rng,
renderer, renderer,
audio, audio,
navigator, navigator,
@ -269,14 +276,15 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
return false; return false;
} }
let (global_time, swf_data, swf_version, background_color, renderer, audio, navigator) = ( let (global_time, swf_data, swf_version, background_color, renderer, audio, navigator, rng) = (
self.global_time, self.global_time,
&mut self.swf_data, &mut self.swf_data,
self.swf_version, self.swf_version,
&mut self.background_color, &mut self.background_color,
&mut self.renderer, &mut self.renderer,
&mut self.audio, &mut self.audio,
&mut self.navigator &mut self.navigator,
&mut self.rng
); );
let mouse_pos = &self.mouse_pos; let mouse_pos = &self.mouse_pos;
@ -295,6 +303,7 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
library: gc_root.library.write(gc_context), library: gc_root.library.write(gc_context),
background_color, background_color,
avm: gc_root.avm.write(gc_context), avm: gc_root.avm.write(gc_context),
rng,
renderer, renderer,
audio, audio,
navigator, navigator,
@ -330,7 +339,7 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
} }
fn preload(&mut self) { fn preload(&mut self) {
let (global_time, swf_data, swf_version, background_color, renderer, audio, navigator) = ( let (global_time, swf_data, swf_version, background_color, renderer, audio, navigator, rng) = (
self.global_time, self.global_time,
&mut self.swf_data, &mut self.swf_data,
self.swf_version, self.swf_version,
@ -338,6 +347,7 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
&mut self.renderer, &mut self.renderer,
&mut self.audio, &mut self.audio,
&mut self.navigator, &mut self.navigator,
&mut self.rng
); );
self.gc_arena.mutate(|gc_context, gc_root| { self.gc_arena.mutate(|gc_context, gc_root| {
@ -348,6 +358,7 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
library: gc_root.library.write(gc_context), library: gc_root.library.write(gc_context),
background_color, background_color,
avm: gc_root.avm.write(gc_context), avm: gc_root.avm.write(gc_context),
rng,
renderer, renderer,
audio, audio,
navigator, navigator,
@ -376,14 +387,15 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
} }
pub fn run_frame(&mut self) { pub fn run_frame(&mut self) {
let (global_time, swf_data, swf_version, background_color, renderer, audio, navigator) = ( let (global_time, swf_data, swf_version, background_color, renderer, audio, navigator, rng) = (
self.global_time, self.global_time,
&mut self.swf_data, &mut self.swf_data,
self.swf_version, self.swf_version,
&mut self.background_color, &mut self.background_color,
&mut self.renderer, &mut self.renderer,
&mut self.audio, &mut self.audio,
&mut self.navigator &mut self.navigator,
&mut self.rng
); );
self.gc_arena.mutate(|gc_context, gc_root| { self.gc_arena.mutate(|gc_context, gc_root| {
@ -394,6 +406,7 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
library: gc_root.library.write(gc_context), library: gc_root.library.write(gc_context),
background_color, background_color,
avm: gc_root.avm.write(gc_context), avm: gc_root.avm.write(gc_context),
rng,
renderer, renderer,
audio, audio,
navigator, navigator,
@ -478,6 +491,7 @@ impl<Audio: AudioBackend, Renderer: RenderBackend, Navigator: NavigatorBackend>
root, root,
start_clip: root, start_clip: root,
active_clip: root, active_clip: root,
rng: update_context.rng,
audio: update_context.audio, audio: update_context.audio,
navigator: update_context.navigator, navigator: update_context.navigator,
}; };
@ -548,6 +562,7 @@ pub struct UpdateContext<'a, 'gc, 'gc_context> {
pub renderer: &'a mut dyn RenderBackend, pub renderer: &'a mut dyn RenderBackend,
pub audio: &'a mut dyn AudioBackend, pub audio: &'a mut dyn AudioBackend,
pub navigator: &'a mut dyn NavigatorBackend, pub navigator: &'a mut dyn NavigatorBackend,
pub rng: &'a mut SmallRng,
pub actions: Vec<(DisplayNode<'gc>, crate::tag_utils::SwfSlice)>, pub actions: Vec<(DisplayNode<'gc>, crate::tag_utils::SwfSlice)>,
pub active_clip: DisplayNode<'gc>, pub active_clip: DisplayNode<'gc>,
} }