Switch to portable RNG in examples (#12644)

# Objective

Fixes issue #12613 - the RNG used in examples is _deterministic_, but
its implementation is not _portable_ across platforms. We want to switch
to using a portable RNG that does not vary across platforms, to ensure
certain examples play out the same way every time.

## Solution

Replace all occurences of `rand::rngs::StdRng` with
`rand_chacha::ChaCha8Rng`, as recommended in issue #12613

---

## Changelog

- Add `rand_chacha` as a new dependency (controversial?)
- Replace all occurences of `rand::rngs::StdRng` with
`rand_chacha::ChaCha8Rng`
This commit is contained in:
Tim Leach 2024-03-22 20:25:49 +00:00 committed by GitHub
parent 92535b4bea
commit b09f3bdfe6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 55 additions and 43 deletions

View file

@ -330,6 +330,7 @@ bevy_internal = { path = "crates/bevy_internal", version = "0.14.0-dev", default
[dev-dependencies]
rand = "0.8.0"
rand_chacha = "0.3.1"
ron = "0.8.0"
flate2 = "1.0"
serde = { version = "1", features = ["derive"] }

View file

@ -7,7 +7,8 @@ use bevy::{
pbr::NotShadowCaster,
prelude::*,
};
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
const INSTRUCTIONS: &str = "\
Controls
@ -48,7 +49,7 @@ fn setup(
));
// cubes
let mut rng = StdRng::seed_from_u64(19878367467713);
let mut rng = ChaCha8Rng::seed_from_u64(19878367467713);
let cube_mesh = meshes.add(Cuboid::new(0.5, 0.5, 0.5));
let blue = materials.add(Color::srgb_u8(124, 144, 255));

View file

@ -14,7 +14,8 @@ use bevy::{
render_asset::RenderAssetUsages,
},
};
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
fn main() {
App::new()
@ -122,7 +123,7 @@ fn setup(
let mesh = meshes.add(mesh);
let mut rng = StdRng::seed_from_u64(42);
let mut rng = ChaCha8Rng::seed_from_u64(42);
for i in -5..5 {
// Create joint entities

View file

@ -3,7 +3,8 @@
use bevy::prelude::*;
// Using crossbeam_channel instead of std as std `Receiver` is `!Sync`
use crossbeam_channel::{bounded, Receiver};
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
use std::time::{Duration, Instant};
fn main() {
@ -26,7 +27,7 @@ fn setup(mut commands: Commands) {
let (tx, rx) = bounded::<u32>(10);
std::thread::spawn(move || {
let mut rng = StdRng::seed_from_u64(19878367467713);
let mut rng = ChaCha8Rng::seed_from_u64(19878367467713);
loop {
// Everything here happens in another thread
// This is where you could connect to an external data source

View file

@ -1,7 +1,8 @@
//! Shows how to iterate over combinations of query results.
use bevy::{color::palettes::css::ORANGE_RED, prelude::*};
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
fn main() {
App::new()
@ -44,7 +45,7 @@ fn generate_bodies(
let color_range = 0.5..1.0;
let vel_range = -0.5..0.5;
let mut rng = StdRng::seed_from_u64(19878367467713);
let mut rng = ChaCha8Rng::seed_from_u64(19878367467713);
for _ in 0..NUM_BODIES {
let radius: f32 = rng.gen_range(0.1..0.7);
let mass_value = radius.powi(3) * 10.;

View file

@ -2,7 +2,8 @@
use bevy::ecs::query::BatchingStrategy;
use bevy::prelude::*;
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
#[derive(Component, Deref)]
struct Velocity(Vec2);
@ -10,7 +11,7 @@ struct Velocity(Vec2);
fn spawn_system(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera2dBundle::default());
let texture = asset_server.load("branding/icon.png");
let mut rng = StdRng::seed_from_u64(19878367467713);
let mut rng = ChaCha8Rng::seed_from_u64(19878367467713);
for _ in 0..128 {
commands.spawn((
SpriteBundle {

View file

@ -3,7 +3,8 @@
use std::f32::consts::PI;
use bevy::prelude::*;
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
#[derive(Clone, Eq, PartialEq, Debug, Hash, Default, States)]
enum GameState {
@ -82,7 +83,7 @@ struct Game {
}
#[derive(Resource, Deref, DerefMut)]
struct Random(StdRng);
struct Random(ChaCha8Rng);
const BOARD_SIZE_I: usize = 14;
const BOARD_SIZE_J: usize = 21;
@ -110,9 +111,9 @@ fn setup_cameras(mut commands: Commands, mut game: ResMut<Game>) {
fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut game: ResMut<Game>) {
let mut rng = if std::env::var("GITHUB_ACTIONS") == Ok("true".to_string()) {
// Make the game play out the same way every time, this is useful for testing purposes.
StdRng::seed_from_u64(19878367467713)
ChaCha8Rng::seed_from_u64(19878367467713)
} else {
StdRng::from_entropy()
ChaCha8Rng::from_entropy()
};
// reset the game state

View file

@ -1,7 +1,8 @@
//! This example demonstrates the implementation and behavior of the axes gizmo.
use bevy::prelude::*;
use bevy::render::primitives::Aabb;
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
use std::f32::consts::PI;
const TRANSITION_DURATION: f32 = 2.0;
@ -34,14 +35,14 @@ struct TransformTracking {
}
#[derive(Resource)]
struct SeededRng(StdRng);
struct SeededRng(ChaCha8Rng);
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let mut rng = StdRng::seed_from_u64(19878367467713);
let mut rng = ChaCha8Rng::seed_from_u64(19878367467713);
// Lights...
commands.spawn(PointLightBundle {

View file

@ -18,7 +18,8 @@ use bevy::{
window::{PresentMode, WindowResolution},
winit::{UpdateMode, WinitSettings},
};
use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng};
use rand::{seq::SliceRandom, Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
const BIRDS_PER_SECOND: u32 = 10000;
const GRAVITY: f32 = -9.8 * 100.0;
@ -181,10 +182,10 @@ struct BirdResources {
textures: Vec<Handle<Image>>,
materials: Vec<Handle<ColorMaterial>>,
quad: Mesh2dHandle,
color_rng: StdRng,
material_rng: StdRng,
velocity_rng: StdRng,
transform_rng: StdRng,
color_rng: ChaCha8Rng,
material_rng: ChaCha8Rng,
velocity_rng: ChaCha8Rng,
transform_rng: ChaCha8Rng,
}
#[derive(Component)]
@ -221,10 +222,10 @@ fn setup(
quad: meshes
.add(Rectangle::from_size(Vec2::splat(BIRD_TEXTURE_SIZE as f32)))
.into(),
color_rng: StdRng::seed_from_u64(42),
material_rng: StdRng::seed_from_u64(42),
velocity_rng: StdRng::seed_from_u64(42),
transform_rng: StdRng::seed_from_u64(42),
color_rng: ChaCha8Rng::seed_from_u64(42),
material_rng: ChaCha8Rng::seed_from_u64(42),
velocity_rng: ChaCha8Rng::seed_from_u64(42),
transform_rng: ChaCha8Rng::seed_from_u64(42),
};
let text_section = move |color: Srgba, value: &str| {
@ -300,11 +301,11 @@ fn mouse_handler(
windows: Query<&Window>,
bird_resources: ResMut<BirdResources>,
mut counter: ResMut<BevyCounter>,
mut rng: Local<Option<StdRng>>,
mut rng: Local<Option<ChaCha8Rng>>,
mut wave: Local<usize>,
) {
if rng.is_none() {
*rng = Some(StdRng::seed_from_u64(42));
*rng = Some(ChaCha8Rng::seed_from_u64(42));
}
let rng = rng.as_mut().unwrap();
let window = windows.single();
@ -332,7 +333,7 @@ fn mouse_handler(
fn bird_velocity_transform(
half_extents: Vec2,
mut translation: Vec3,
velocity_rng: &mut StdRng,
velocity_rng: &mut ChaCha8Rng,
waves: Option<usize>,
dt: f32,
) -> (Transform, Vec3) {
@ -537,7 +538,7 @@ fn counter_system(
}
fn init_textures(textures: &mut Vec<Handle<Image>>, args: &Args, images: &mut Assets<Image>) {
let mut color_rng = StdRng::seed_from_u64(42);
let mut color_rng = ChaCha8Rng::seed_from_u64(42);
while textures.len() < args.material_texture_count {
let pixel = [color_rng.gen(), color_rng.gen(), color_rng.gen(), 255];
textures.push(images.add(Image::new_fill(
@ -572,8 +573,8 @@ fn init_materials(
texture: textures.first().cloned(),
}));
let mut color_rng = StdRng::seed_from_u64(42);
let mut texture_rng = StdRng::seed_from_u64(42);
let mut color_rng = ChaCha8Rng::seed_from_u64(42);
let mut texture_rng = ChaCha8Rng::seed_from_u64(42);
materials.extend(
std::iter::repeat_with(|| {
assets.add(ColorMaterial {

View file

@ -23,7 +23,8 @@ use bevy::{
window::{PresentMode, WindowResolution},
winit::{UpdateMode, WinitSettings},
};
use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng};
use rand::{seq::SliceRandom, Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
#[derive(FromArgs, Resource)]
/// `many_cubes` stress test
@ -123,7 +124,7 @@ fn setup(
let material_textures = init_textures(args, images);
let materials = init_materials(args, &material_textures, material_assets);
let mut material_rng = StdRng::seed_from_u64(42);
let mut material_rng = ChaCha8Rng::seed_from_u64(42);
match args.layout {
Layout::Sphere => {
// NOTE: This pattern is good for testing performance of culling as it provides roughly
@ -202,7 +203,7 @@ fn setup(
}
fn init_textures(args: &Args, images: &mut Assets<Image>) -> Vec<Handle<Image>> {
let mut color_rng = StdRng::seed_from_u64(42);
let mut color_rng = ChaCha8Rng::seed_from_u64(42);
let color_bytes: Vec<u8> = (0..(args.material_texture_count * 4))
.map(|i| if (i % 4) == 3 { 255 } else { color_rng.gen() })
.collect();
@ -246,8 +247,8 @@ fn init_materials(
..default()
}));
let mut color_rng = StdRng::seed_from_u64(42);
let mut texture_rng = StdRng::seed_from_u64(42);
let mut color_rng = ChaCha8Rng::seed_from_u64(42);
let mut texture_rng = ChaCha8Rng::seed_from_u64(42);
materials.extend(
std::iter::repeat_with(|| {
assets.add(StandardMaterial {

View file

@ -6,7 +6,8 @@ use bevy::color::{
};
use bevy::input::mouse::{MouseButton, MouseButtonInput, MouseMotion};
use bevy::prelude::*;
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
use std::f32::consts::PI;
fn main() {
@ -44,7 +45,7 @@ struct Instructions;
struct MousePressed(bool);
#[derive(Resource)]
struct SeededRng(StdRng);
struct SeededRng(ChaCha8Rng);
// Setup
@ -53,7 +54,7 @@ fn setup(
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let mut seeded_rng = StdRng::seed_from_u64(19878367467712);
let mut seeded_rng = ChaCha8Rng::seed_from_u64(19878367467712);
// A camera looking at the origin
commands.spawn(Camera3dBundle {

View file

@ -2,7 +2,8 @@
//! Bevy uses `FontAtlas`'s under the hood to optimize text rendering.
use bevy::{color::palettes::basic::YELLOW, prelude::*, text::FontAtlasSets};
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
fn main() {
App::new()
@ -32,7 +33,7 @@ impl Default for State {
}
#[derive(Resource, Deref, DerefMut)]
struct SeededRng(StdRng);
struct SeededRng(ChaCha8Rng);
fn atlas_render_system(
mut commands: Commands,
@ -104,5 +105,5 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut state: ResM
},
));
});
commands.insert_resource(SeededRng(StdRng::seed_from_u64(19878367467713)));
commands.insert_resource(SeededRng(ChaCha8Rng::seed_from_u64(19878367467713)));
}