From 946e961633d4a7ecdfd0241042526285ce2e5922 Mon Sep 17 00:00:00 2001 From: Michael Bradley Date: Sun, 23 Mar 2025 22:32:57 -0400 Subject: [PATCH] Make RNG seedable --- Cargo.lock | 1 + Cargo.toml | 1 + src/lib.rs | 2 ++ src/main.rs | 34 ++++++++++++++++++++-------------- src/random.rs | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 src/lib.rs create mode 100644 src/random.rs diff --git a/Cargo.lock b/Cargo.lock index 4180317..01267cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1607,6 +1607,7 @@ dependencies = [ "bevy", "log", "rand 0.9.0", + "rand_chacha 0.9.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 68b934e..9c260e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,3 +34,4 @@ log = { version = "*", features = [ "release_max_level_warn", ] } rand = "0.9.0" +rand_chacha = "0.9.0" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d2c9234 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +mod random; +pub use random::Random; diff --git a/src/main.rs b/src/main.rs index 7878fc1..6c51414 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,18 +9,26 @@ use bevy::{ input::common_conditions::input_pressed, prelude::*, }; -use rand::Rng; + +use distributed_physics_test::Random; const AREA_WIDTH: f32 = 750.; const PLAYER_SIZE: f32 = 30.; -fn main() { +#[derive(Default)] +struct AppSettings { + seed: String, +} + +fn main() -> AppExit { + run_app(AppSettings::default()) +} + +fn run_app(settings: AppSettings) -> AppExit { App::new() .add_plugins(( DefaultPlugins, - PhysicsPlugins::default() - .with_length_unit(50.0) - .set(PhysicsInterpolationPlugin::interpolate_all()), + PhysicsPlugins::default().with_length_unit(50.0), )) .add_systems( Startup, @@ -31,11 +39,12 @@ fn main() { (move_player, quit.run_if(input_pressed(KeyCode::KeyQ))), ) .insert_resource(Gravity(Vector::ZERO)) - .run(); + .insert_resource(Random::seed(&settings.seed)) + .run() } fn setup_scene(mut commands: Commands) { - commands.spawn(Camera2d); + commands.spawn((Name::new("Camera"), Camera2d, IsDefaultUiCamera)); } #[derive(Component, Default)] @@ -50,19 +59,16 @@ fn setup_balls( mut commands: Commands, mut materials: ResMut>, mut meshes: ResMut>, + mut rng: ResMut, ) { - let mut rng = rand::rng(); for _ in 0..20 { - let circle = Circle::new(rng.random_range(10.0..(PLAYER_SIZE - 5.))); + let circle = Circle::new(rng.range(10.0..(PLAYER_SIZE - 5.))); let mut transform = Transform::from_xyz( 0., - rng.random_range((PLAYER_SIZE + 5.)..(AREA_WIDTH / 2. - PLAYER_SIZE)), + rng.range((PLAYER_SIZE + 5.)..(AREA_WIDTH / 2. - PLAYER_SIZE)), 0., ); - transform.rotate_around( - Vec3::ZERO, - Quat::from_rotation_z(rng.random_range(0.0..(PI * 2.))), - ); + transform.rotate_around(Vec3::ZERO, Quat::from_rotation_z(rng.range(0.0..(PI * 2.)))); commands.spawn(( Ball, Collider::from(circle), diff --git a/src/random.rs b/src/random.rs new file mode 100644 index 0000000..490003d --- /dev/null +++ b/src/random.rs @@ -0,0 +1,33 @@ +use std::hash::{DefaultHasher, Hash, Hasher}; + +use bevy::prelude::*; +use rand::{ + Rng, SeedableRng, + distr::uniform::{SampleRange, SampleUniform}, +}; +use rand_chacha::ChaCha8Rng; + +#[derive(Resource)] +pub struct Random(ChaCha8Rng); + +impl Random { + pub fn seed(seed: &String) -> Self { + Random(ChaCha8Rng::seed_from_u64( + seed.parse::().unwrap_or_else(|_| hash_string(seed)), + )) + } + + pub fn range(&mut self, range: R) -> T + where + T: SampleUniform, + R: SampleRange, + { + self.0.random_range(range) + } +} + +fn hash_string(string: &String) -> u64 { + let mut state = DefaultHasher::new(); + string.hash(&mut state); + state.finish() +}