From 82ba8c5ae2a7571ec3c6017f813f198d4e960205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Rica=20Pais=20da=20Silva?= Date: Tue, 17 Oct 2023 11:31:14 +0200 Subject: [PATCH 01/11] refactor: Forking via traits --- Cargo.toml | 7 ++- README.md | 21 ++++--- bevy_prng/Cargo.toml | 4 +- bevy_prng/README.md | 7 ++- bevy_prng/src/lib.rs | 66 +++++++++++++++++--- src/component.rs | 39 ++++++++++-- src/lib.rs | 3 +- src/plugin.rs | 3 +- src/prelude.rs | 2 +- src/resource.rs | 50 +++++++++++++-- src/thread_local_entropy.rs | 2 +- src/traits.rs | 121 +++++++++++++----------------------- tests/determinism.rs | 8 +-- 13 files changed, 212 insertions(+), 121 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a1d30cc..09306ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_rand" -version = "0.3.0" +version = "0.4.0" edition = "2021" authors = ["Gonçalo Rica Pais da Silva "] description = "A plugin to integrate rand for ECS optimised RNG for the Bevy game engine." @@ -22,7 +22,8 @@ members = ["bevy_prng"] [dependencies] # bevy -bevy = { version = "0.11", default-features = false } +bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "1258ceb62cd8acb61f031dce128c2e04ee058538", version = "0.12.0-dev", default-features = false } +bevy_prng = { path = "bevy_prng", version = "0.2" } # others serde = { version = "1.0", features = ["derive"], optional = true } @@ -30,7 +31,7 @@ rand_core = { version = "0.6", features = ["std"] } rand_chacha = { version = "0.3", optional = true } [dev-dependencies] -bevy_prng = { path = "bevy_prng", version = "0.1", features = ["rand_chacha"] } +bevy_prng = { path = "bevy_prng", version = "0.2", features = ["rand_chacha"] } rand = "0.8" ron = { version = "0.8.0", features = ["integer128"] } diff --git a/README.md b/README.md index 49ecc20..7b43701 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Bevy Rand operates around a global entropy source provided as a resource, and th If cloning creates a second instance that shares the same state as the original, forking derives a new state from the original, leaving the original 'changed' and the new instance with a randomised seed. Forking RNG instances from a global source is a way to ensure that one seed produces many deterministic states, while making it difficult to predict outputs from many sources and also ensuring no one source shares the same state either with the original or with each other. -Bevy Rand approaches forking via `From` implementations of the various component/resource types, making it straightforward to use. +Bevy Rand provides forking via `ForkableRng`/`ForkableAsRng`/`ForkableInnerRng` traits, allowing one to easily fork with just a simple `.fork_rng()` method call, and also with `From` implementations of the various component/resource types, making it straightforward to use. ## Using Bevy Rand @@ -96,7 +96,7 @@ fn print_random_value(mut rng: ResMut>) { ### Forking RNGs -For seeding `EntropyComponent`s from a global source, it is best to make use of forking instead of generating the seed value directly. +For seeding `EntropyComponent`s from a global source, it is best to make use of forking instead of generating the seed value directly. `GlobalEntropy` can only exist as a singular instance, so when forking normally, it will always fork as `EntropyComponent` instances. ```rust use bevy::prelude::*; @@ -110,7 +110,7 @@ fn setup_source(mut commands: Commands, mut global: ResMut"] description = "A crate providing newtyped RNGs for integration into Bevy." @@ -24,7 +24,7 @@ serialize = [ ] [dependencies] -bevy = { version = "0.11", default-features = false } +bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "1258ceb62cd8acb61f031dce128c2e04ee058538", version = "0.12.0-dev", default-features = false } rand_core = { version = "0.6", features = ["std"] } serde = { version = "1.0", features = ["derive"], optional = true } rand_chacha = { version = "0.3", optional = true } diff --git a/bevy_prng/README.md b/bevy_prng/README.md index 28cb509..b276874 100644 --- a/bevy_prng/README.md +++ b/bevy_prng/README.md @@ -44,9 +44,10 @@ All the below crates implement the necessary traits to be compatible with `bevy_ `bevy_prng` uses the same MSRV as `bevy`. -| `bevy` | `bevy_prng` | -| -------- | ----------- | -| v0.11 | v0.1 | +| `bevy` | `bevy_prng` | +| ------ | ----------- | +| v0.12 | v0.2 | +| v0.11 | v0.1 | ## License diff --git a/bevy_prng/src/lib.rs b/bevy_prng/src/lib.rs index bf64893..8bba274 100644 --- a/bevy_prng/src/lib.rs +++ b/bevy_prng/src/lib.rs @@ -2,20 +2,22 @@ #![deny(missing_docs)] #![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(docsrs, allow(unused_attributes))] + +use std::fmt::Debug; + +use bevy::{ + prelude::{FromReflect, Reflect}, + reflect::{GetTypeRegistration, TypePath}, +}; +use rand_core::{RngCore, SeedableRng}; + #[cfg(any( feature = "wyrand", feature = "rand_chacha", feature = "rand_pcg", feature = "rand_xoshiro" ))] -use bevy::prelude::{Reflect, ReflectFromReflect}; -#[cfg(any( - feature = "wyrand", - feature = "rand_chacha", - feature = "rand_pcg", - feature = "rand_xoshiro" -))] -use rand_core::{RngCore, SeedableRng}; +use bevy::prelude::ReflectFromReflect; #[cfg(all( any( @@ -39,6 +41,52 @@ use bevy::prelude::{ReflectDeserialize, ReflectSerialize}; ))] use serde::{Deserialize, Serialize}; +/// A marker trait to define the required trait bounds for a seedable PRNG to +/// integrate into `EntropyComponent` or `GlobalEntropy`. This is a sealed trait. +#[cfg(feature = "serialize")] +pub trait SeedableEntropySource: + RngCore + + SeedableRng + + Clone + + Debug + + PartialEq + + Sync + + Send + + Reflect + + TypePath + + FromReflect + + GetTypeRegistration + + Serialize + + for<'a> Deserialize<'a> + + private::SealedSeedable +{ +} + +/// A marker trait to define the required trait bounds for a seedable PRNG to +/// integrate into `EntropyComponent` or `GlobalEntropy`. This is a sealed trait. +#[cfg(not(feature = "serialize"))] +pub trait SeedableEntropySource: + RngCore + + SeedableRng + + Clone + + Debug + + PartialEq + + Reflect + + TypePath + + FromReflect + + GetTypeRegistration + + Sync + + Send + + private::SealedSeedable +{ +} + +mod private { + pub trait SealedSeedable {} + + impl SealedSeedable for T {} +} + #[cfg(any( feature = "wyrand", feature = "rand_chacha", @@ -108,6 +156,8 @@ macro_rules! newtype_prng { Self::new(value) } } + + impl SeedableEntropySource for $newtype {} }; } diff --git a/src/component.rs b/src/component.rs index 19d35a7..763899e 100644 --- a/src/component.rs +++ b/src/component.rs @@ -1,7 +1,11 @@ use std::fmt::Debug; -use crate::{resource::GlobalEntropy, traits::SeedableEntropySource}; +use crate::{ + resource::GlobalEntropy, + traits::{EcsEntropySource, ForkableAsRng, ForkableInnerRng, ForkableRng}, +}; use bevy::prelude::{Component, Mut, Reflect, ReflectComponent, ReflectFromReflect, ResMut}; +use bevy_prng::SeedableEntropySource; use rand_core::{RngCore, SeedableRng}; #[cfg(feature = "thread_local_entropy")] @@ -175,6 +179,8 @@ impl SeedableRng for EntropyComponent { } } +impl EcsEntropySource for EntropyComponent {} + impl From for EntropyComponent { fn from(value: R) -> Self { Self::new(value) @@ -203,6 +209,27 @@ impl From<&mut ResMut<'_, GlobalEntropy>> } } +impl ForkableRng for EntropyComponent +where + R: SeedableEntropySource + 'static, +{ + type Output = EntropyComponent; +} + +impl ForkableAsRng for EntropyComponent +where + R: SeedableEntropySource + 'static, +{ + type Output = EntropyComponent where T: SeedableEntropySource; +} + +impl ForkableInnerRng for EntropyComponent +where + R: SeedableEntropySource + 'static, +{ + type Output = R; +} + #[cfg(test)] mod tests { use bevy::reflect::TypePath; @@ -214,7 +241,7 @@ mod tests { fn forking() { let mut rng1 = EntropyComponent::::default(); - let rng2 = EntropyComponent::from(&mut rng1); + let rng2 = rng1.fork_rng(); assert_ne!( rng1, rng2, @@ -240,12 +267,12 @@ mod tests { fn rng_untyped_serialization() { use bevy::reflect::{ serde::{ReflectSerializer, UntypedReflectDeserializer}, - TypeRegistryInternal, + TypeRegistry, }; use ron::to_string; use serde::de::DeserializeSeed; - let mut registry = TypeRegistryInternal::default(); + let mut registry = TypeRegistry::default(); registry.register::>(); let mut val: EntropyComponent = EntropyComponent::from_seed([7; 32]); @@ -288,12 +315,12 @@ mod tests { fn rng_typed_serialization() { use bevy::reflect::{ serde::{TypedReflectDeserializer, TypedReflectSerializer}, - GetTypeRegistration, TypeRegistryInternal, + GetTypeRegistration, TypeRegistry, }; use ron::ser::to_string; use serde::de::DeserializeSeed; - let mut registry = TypeRegistryInternal::default(); + let mut registry = TypeRegistry::default(); registry.register::>(); let registered_type = EntropyComponent::::get_type_registration(); diff --git a/src/lib.rs b/src/lib.rs index 9ee9663..400d0d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,4 +14,5 @@ pub mod prelude; pub mod resource; #[cfg(feature = "thread_local_entropy")] mod thread_local_entropy; -mod traits; +/// Traits for enabling utility methods for [`crate::component::EntropyComponent`] and [`crate::resource::GlobalEntropy`]. +pub mod traits; diff --git a/src/plugin.rs b/src/plugin.rs index fa4d580..d2c6232 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,5 +1,6 @@ -use crate::{component::EntropyComponent, resource::GlobalEntropy, traits::SeedableEntropySource}; +use crate::{component::EntropyComponent, resource::GlobalEntropy}; use bevy::prelude::{App, Plugin}; +use bevy_prng::SeedableEntropySource; use rand_core::SeedableRng; /// Plugin for integrating a PRNG that implements `RngCore` into diff --git a/src/prelude.rs b/src/prelude.rs index 564a6b2..a77e8a1 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,4 +1,4 @@ pub use crate::component::EntropyComponent; pub use crate::plugin::EntropyPlugin; pub use crate::resource::GlobalEntropy; -pub use crate::traits::SeedableEntropySource; +pub use crate::traits::{EcsEntropySource, ForkableAsRng, ForkableInnerRng, ForkableRng}; diff --git a/src/resource.rs b/src/resource.rs index 250e37b..21d79ea 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -1,7 +1,11 @@ use std::fmt::Debug; -use crate::traits::SeedableEntropySource; +use crate::{ + component::EntropyComponent, + traits::{EcsEntropySource, ForkableAsRng, ForkableInnerRng, ForkableRng}, +}; use bevy::prelude::{Reflect, ReflectFromReflect, ReflectResource, Resource}; +use bevy_prng::SeedableEntropySource; use rand_core::{RngCore, SeedableRng}; #[cfg(feature = "thread_local_entropy")] @@ -120,6 +124,8 @@ impl SeedableRng for GlobalEntropy { } } +impl EcsEntropySource for GlobalEntropy {} + impl From for GlobalEntropy { fn from(value: R) -> Self { Self::new(value) @@ -132,6 +138,27 @@ impl From<&mut R> for GlobalEntropy { } } +impl ForkableRng for GlobalEntropy +where + R: SeedableEntropySource + 'static, +{ + type Output = EntropyComponent; +} + +impl ForkableAsRng for GlobalEntropy +where + R: SeedableEntropySource + 'static, +{ + type Output = EntropyComponent where T: SeedableEntropySource; +} + +impl ForkableInnerRng for GlobalEntropy +where + R: SeedableEntropySource + 'static, +{ + type Output = R; +} + #[cfg(test)] mod tests { use bevy::reflect::TypePath; @@ -152,17 +179,30 @@ mod tests { ); } + #[test] + fn forking_into_component() { + let mut source: GlobalEntropy = GlobalEntropy::::from_seed([1; 32]); + + let mut forked = source.fork_rng(); + + let source_val = source.next_u32(); + + let forked_val = forked.next_u32(); + + assert_ne!(source_val, forked_val); + } + #[cfg(feature = "serialize")] #[test] fn rng_untyped_serialization() { use bevy::reflect::{ serde::{ReflectSerializer, UntypedReflectDeserializer}, - TypeRegistryInternal, + TypeRegistry, }; use ron::ser::to_string; use serde::de::DeserializeSeed; - let mut registry = TypeRegistryInternal::default(); + let mut registry = TypeRegistry::default(); registry.register::>(); let mut val = GlobalEntropy::::from_seed([7; 32]); @@ -205,12 +245,12 @@ mod tests { fn rng_typed_serialization() { use bevy::reflect::{ serde::{TypedReflectDeserializer, TypedReflectSerializer}, - GetTypeRegistration, TypeRegistryInternal, + GetTypeRegistration, TypeRegistry, }; use ron::to_string; use serde::de::DeserializeSeed; - let mut registry = TypeRegistryInternal::default(); + let mut registry = TypeRegistry::default(); registry.register::>(); let registered_type = GlobalEntropy::::get_type_registration(); diff --git a/src/thread_local_entropy.rs b/src/thread_local_entropy.rs index 72885b0..15e2a76 100644 --- a/src/thread_local_entropy.rs +++ b/src/thread_local_entropy.rs @@ -24,7 +24,7 @@ impl ThreadLocalEntropy { #[inline] #[must_use] pub(crate) fn new() -> Self { - Self(SOURCE.with(|source| Rc::clone(source))) + Self(SOURCE.with(Rc::clone)) } } diff --git a/src/traits.rs b/src/traits.rs index c50bb49..47b0492 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,89 +1,56 @@ -use std::fmt::Debug; - -use bevy::reflect::{FromReflect, GetTypeRegistration, Reflect, TypePath}; +use bevy_prng::SeedableEntropySource; use rand_core::{RngCore, SeedableRng}; -#[cfg(feature = "serialize")] -use serde::{Deserialize, Serialize}; - -/// A wrapper trait to encapsulate the required trait bounds for a seedable PRNG to -/// integrate into [`crate::component::EntropyComponent`] or -/// [`crate::resource::GlobalEntropy`]. This is a sealed trait. -#[cfg(feature = "serialize")] -pub trait SeedableEntropySource: - RngCore - + SeedableRng - + Clone - + Debug - + PartialEq - + Sync - + Send - + Reflect - + TypePath - + FromReflect - + GetTypeRegistration - + Serialize - + for<'a> Deserialize<'a> - + private::SealedSeedable -{ +/// Trait for implementing Forking behaviour for [`crate::component::EntropyComponent`] and [`crate::resource::GlobalEntropy`]. +/// Forking creates a new RNG instance using a generated seed from the original source. If the original is seeded with a known +/// seed, this process is deterministic. +pub trait ForkableRng: EcsEntropySource { + /// The type of instance that is to be forked from the original source. + type Output: EcsEntropySource; + + /// Fork the original instance to yield a new instance with a generated seed. + /// This method preserves the RNG algorithm between original and forked instances. + fn fork_rng(&mut self) -> Self::Output { + Self::Output::from_rng(self).unwrap() + } } -#[cfg(feature = "serialize")] -impl SeedableEntropySource for T where - T: RngCore - + SeedableRng - + Clone - + Debug - + PartialEq - + Sync - + Send - + Reflect - + TypePath - + FromReflect - + GetTypeRegistration - + Serialize - + for<'a> Deserialize<'a> -{ +/// Trait for implementing Forking behaviour for [`crate::component::EntropyComponent`] and [`crate::resource::GlobalEntropy`]. +/// Forking creates a new RNG instance using a generated seed from the original source. If the original is seeded with a known +/// seed, this process is deterministic. This trait enables forking between different PRNG algorithm types. +pub trait ForkableAsRng: EcsEntropySource { + /// The type of instance that is to be forked from the original source. + type Output: EcsEntropySource + where + R: SeedableEntropySource; + + /// Fork the original instance to yield a new instance with a generated seed. + /// This method allows one to specify the RNG algorithm to be used for the forked instance. + fn fork_as(&mut self) -> Self::Output { + Self::Output::<_>::from_rng(self).unwrap() + } } -/// A wrapper trait to encapsulate the required trait bounds for a seedable PRNG to -/// integrate into [`crate::component::EntropyComponent`] or -/// [`crate::resource::GlobalEntropy`]. This is a sealed trait. -#[cfg(not(feature = "serialize"))] -pub trait SeedableEntropySource: - RngCore - + SeedableRng - + Clone - + Debug - + PartialEq - + Reflect - + TypePath - + FromReflect - + GetTypeRegistration - + Sync - + Send - + private::SealedSeedable -{ +/// Trait for implementing Forking behaviour for [`crate::component::EntropyComponent`] and [`crate::resource::GlobalEntropy`]. +/// Forking creates a new RNG instance using a generated seed from the original source. If the original is seeded with a known +/// seed, this process is deterministic. This trait enables forking the inner PRNG instance of the source component/resource. +pub trait ForkableInnerRng: EcsEntropySource { + /// The type of instance that is to be forked from the original source. + type Output: SeedableEntropySource; + + /// Fork the original instance to yield a new instance with a generated seed. + /// This method yields the inner PRNG instance directly as a forked instance. + fn fork_inner(&mut self) -> Self::Output { + Self::Output::from_rng(self).unwrap() + } } -#[cfg(not(feature = "serialize"))] -impl SeedableEntropySource for T where - T: RngCore - + SeedableRng - + Clone - + Debug - + PartialEq - + Reflect - + TypePath - + FromReflect - + GetTypeRegistration - + Sync - + Send -{ -} +/// A marker trait for [`crate::component::EntropyComponent`] and [`crate::resource::GlobalEntropy`]. +/// This is a sealed trait and cannot be consumed by downstream. +pub trait EcsEntropySource: RngCore + SeedableRng + private::SealedSource {} mod private { - pub trait SealedSeedable {} + pub trait SealedSource {} - impl SealedSeedable for T {} + impl SealedSource for T {} } diff --git a/tests/determinism.rs b/tests/determinism.rs index 7769029..aa56a2d 100644 --- a/tests/determinism.rs +++ b/tests/determinism.rs @@ -60,13 +60,13 @@ fn random_output_d(mut q_source: Query<&mut EntropyComponent, With>) { - commands.spawn((SourceA, EntropyComponent::from(&mut rng))); + commands.spawn((SourceA, rng.fork_as::())); - commands.spawn((SourceB, EntropyComponent::from(&mut rng))); + commands.spawn((SourceB, rng.fork_rng())); - commands.spawn((SourceC, EntropyComponent::from(&mut rng))); + commands.spawn((SourceC, rng.fork_rng())); - commands.spawn((SourceD, EntropyComponent::from(&mut rng))); + commands.spawn((SourceD, rng.fork_rng())); } /// Entities having their own sources side-steps issues with parallel execution and scheduling From adc878442cc9469f5e88d95e723520fb6a62ae19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Rica=20Pais=20da=20Silva?= Date: Tue, 17 Oct 2023 15:06:00 +0200 Subject: [PATCH 02/11] fix: serde imports --- bevy_prng/src/lib.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/bevy_prng/src/lib.rs b/bevy_prng/src/lib.rs index 8bba274..14f2ce0 100644 --- a/bevy_prng/src/lib.rs +++ b/bevy_prng/src/lib.rs @@ -30,15 +30,7 @@ use bevy::prelude::ReflectFromReflect; ))] use bevy::prelude::{ReflectDeserialize, ReflectSerialize}; -#[cfg(all( - any( - feature = "wyrand", - feature = "rand_chacha", - feature = "rand_pcg", - feature = "rand_xoshiro" - ), - feature = "serialize" -))] +#[cfg(feature = "serialize")] use serde::{Deserialize, Serialize}; /// A marker trait to define the required trait bounds for a seedable PRNG to From b627481d77c9da9a76bfd0c5509fc8ea43ab799c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Rica=20Pais=20da=20Silva?= Date: Wed, 18 Oct 2023 07:20:05 +0200 Subject: [PATCH 03/11] docs: Update example and add code snippets for trait --- examples/turn_based_game.rs | 4 +-- src/traits.rs | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/examples/turn_based_game.rs b/examples/turn_based_game.rs index f07ebfe..d17acc0 100644 --- a/examples/turn_based_game.rs +++ b/examples/turn_based_game.rs @@ -74,7 +74,7 @@ fn setup_player(mut commands: Commands, mut rng: ResMut>) { + /// commands + /// .spawn(( + /// Source, + /// global.fork_rng(), + /// )); + /// } + /// ``` fn fork_rng(&mut self) -> Self::Output { Self::Output::from_rng(self).unwrap() } @@ -26,6 +42,22 @@ pub trait ForkableAsRng: EcsEntropySource { /// Fork the original instance to yield a new instance with a generated seed. /// This method allows one to specify the RNG algorithm to be used for the forked instance. + /// ``` + /// use bevy::prelude::*; + /// use bevy_rand::prelude::*; + /// use bevy_prng::{ChaCha8Rng, ChaCha12Rng}; + /// + /// #[derive(Component)] + /// struct Source; + /// + /// fn setup_source(mut commands: Commands, mut global: ResMut>) { + /// commands + /// .spawn(( + /// Source, + /// global.fork_as::(), + /// )); + /// } + /// ``` fn fork_as(&mut self) -> Self::Output { Self::Output::<_>::from_rng(self).unwrap() } @@ -40,6 +72,25 @@ pub trait ForkableInnerRng: EcsEntropySource { /// Fork the original instance to yield a new instance with a generated seed. /// This method yields the inner PRNG instance directly as a forked instance. + /// ``` + /// use bevy::prelude::*; + /// use bevy_rand::prelude::*; + /// use bevy_prng::ChaCha8Rng; + /// use rand_core::RngCore; + /// + /// #[derive(Component)] + /// struct Source; + /// + /// fn do_random_action(source: &mut ChaCha8Rng) { + /// println!("Random value: {}", source.next_u32()); + /// } + /// + /// fn access_source(mut global: ResMut>) { + /// let mut source = global.fork_inner(); + /// + /// do_random_action(&mut source); + /// } + /// ``` fn fork_inner(&mut self) -> Self::Output { Self::Output::from_rng(self).unwrap() } From 45d3628a3dcfd9e2373f360b12caefc90507e26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Rica=20Pais=20da=20Silva?= Date: Wed, 18 Oct 2023 07:50:08 +0200 Subject: [PATCH 04/11] docs: More examples using fork methods --- src/component.rs | 4 ++-- src/prelude.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/component.rs b/src/component.rs index 763899e..5ac9da9 100644 --- a/src/component.rs +++ b/src/component.rs @@ -59,7 +59,7 @@ use serde::{Deserialize, Serialize}; /// commands /// .spawn(( /// Source, -/// EntropyComponent::from(&mut global), +/// global.fork_rng(), /// )); /// } /// ``` @@ -85,7 +85,7 @@ use serde::{Deserialize, Serialize}; /// commands /// .spawn(( /// Npc, -/// EntropyComponent::from(&mut source) +/// source.fork_rng() /// )); /// } /// } diff --git a/src/prelude.rs b/src/prelude.rs index a77e8a1..4482719 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,4 +1,4 @@ pub use crate::component::EntropyComponent; pub use crate::plugin::EntropyPlugin; pub use crate::resource::GlobalEntropy; -pub use crate::traits::{EcsEntropySource, ForkableAsRng, ForkableInnerRng, ForkableRng}; +pub use crate::traits::{ForkableAsRng, ForkableInnerRng, ForkableRng}; From ca545ebff888834bc3aff719102b7908944671be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Rica=20Pais=20da=20Silva?= Date: Wed, 18 Oct 2023 09:48:51 +0200 Subject: [PATCH 05/11] test: Add more forking tests --- src/component.rs | 12 ++++++++++++ src/resource.rs | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/component.rs b/src/component.rs index 5ac9da9..696bddb 100644 --- a/src/component.rs +++ b/src/component.rs @@ -249,6 +249,18 @@ mod tests { ); } + #[test] + fn forking_inner() { + let mut rng1 = EntropyComponent::::default(); + + let rng2 = rng1.fork_inner(); + + assert_ne!( + rng1.0, rng2, + "forked ChaCha8Rngs should not match each other" + ); + } + #[test] fn type_paths() { assert_eq!( diff --git a/src/resource.rs b/src/resource.rs index 21d79ea..30eb120 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -192,6 +192,18 @@ mod tests { assert_ne!(source_val, forked_val); } + #[test] + fn forking_inner() { + let mut rng1 = GlobalEntropy::::default(); + + let rng2 = rng1.fork_inner(); + + assert_ne!( + rng1.0, rng2, + "forked ChaCha8Rngs should not match each other" + ); + } + #[cfg(feature = "serialize")] #[test] fn rng_untyped_serialization() { From 39516abd1e7fe7c08da5f995da5567c21dcce24c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Rica=20Pais=20da=20Silva?= Date: Wed, 18 Oct 2023 10:23:44 +0200 Subject: [PATCH 06/11] docs: Add deprecation note on From forking --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7b43701..32fe4ed 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Bevy Rand operates around a global entropy source provided as a resource, and th If cloning creates a second instance that shares the same state as the original, forking derives a new state from the original, leaving the original 'changed' and the new instance with a randomised seed. Forking RNG instances from a global source is a way to ensure that one seed produces many deterministic states, while making it difficult to predict outputs from many sources and also ensuring no one source shares the same state either with the original or with each other. -Bevy Rand provides forking via `ForkableRng`/`ForkableAsRng`/`ForkableInnerRng` traits, allowing one to easily fork with just a simple `.fork_rng()` method call, and also with `From` implementations of the various component/resource types, making it straightforward to use. +Bevy Rand provides forking via `ForkableRng`/`ForkableAsRng`/`ForkableInnerRng` traits, allowing one to easily fork with just a simple `.fork_rng()` method call, making it straightforward to use. There's also `From` implementations, but from v0.4 onwards, these are considered deprecated and will likely be removed/changed in a future version. ## Using Bevy Rand From d9ba2d8dd18252c9984a76568cf7e4d80dee0753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Rica=20Pais=20da=20Silva?= Date: Wed, 18 Oct 2023 12:16:43 +0200 Subject: [PATCH 07/11] test: Even more forking tests --- src/component.rs | 14 +++++++++++++- src/resource.rs | 14 +++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/component.rs b/src/component.rs index 696bddb..cf4f949 100644 --- a/src/component.rs +++ b/src/component.rs @@ -233,7 +233,7 @@ where #[cfg(test)] mod tests { use bevy::reflect::TypePath; - use bevy_prng::ChaCha8Rng; + use bevy_prng::{ChaCha8Rng, ChaCha12Rng}; use super::*; @@ -249,6 +249,18 @@ mod tests { ); } + #[test] + fn forking_as() { + let mut rng1 = EntropyComponent::::default(); + + let rng2 = rng1.fork_as::(); + + let rng1 = format!("{:?}", rng1); + let rng2 = format!("{:?}", rng2); + + assert_ne!(&rng1, &rng2, "forked EntropyComponents should not match each other"); + } + #[test] fn forking_inner() { let mut rng1 = EntropyComponent::::default(); diff --git a/src/resource.rs b/src/resource.rs index 30eb120..a841daf 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -162,7 +162,7 @@ where #[cfg(test)] mod tests { use bevy::reflect::TypePath; - use bevy_prng::ChaCha8Rng; + use bevy_prng::{ChaCha8Rng, ChaCha12Rng}; use super::*; @@ -192,6 +192,18 @@ mod tests { assert_ne!(source_val, forked_val); } + #[test] + fn forking_as() { + let mut rng1 = GlobalEntropy::::default(); + + let rng2 = rng1.fork_as::(); + + let rng1 = format!("{:?}", rng1); + let rng2 = format!("{:?}", rng2); + + assert_ne!(&rng1, &rng2, "GlobalEntropy should not match the forked component"); + } + #[test] fn forking_inner() { let mut rng1 = GlobalEntropy::::default(); From 73ba917ed469c320e73a3c9b6b2a75d2df0edadc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Rica=20Pais=20da=20Silva?= Date: Fri, 20 Oct 2023 09:12:18 +0200 Subject: [PATCH 08/11] fix: Lockstep versioning and test different PRNG conversions --- Cargo.toml | 9 ++++++++- src/resource.rs | 4 ++-- tests/determinism.rs | 31 ++++++++++++++++++++++++++----- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 09306ab..6bf9e8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,8 +30,15 @@ serde = { version = "1.0", features = ["derive"], optional = true } rand_core = { version = "0.6", features = ["std"] } rand_chacha = { version = "0.3", optional = true } +# This cfg cannot be enabled, but it forces Cargo to keep bevy_prng's +# version in lockstep with bevy_rand, so that even minor versions +# cannot be out of step with bevy_rand due to dependencies on traits +# and implementations between the two crates. +[target.'cfg(any())'.dependencies] +bevy_prng = { path = "bevy_prng", version = "=0.2" } + [dev-dependencies] -bevy_prng = { path = "bevy_prng", version = "0.2", features = ["rand_chacha"] } +bevy_prng = { path = "bevy_prng", version = "0.2", features = ["rand_chacha", "wyrand"] } rand = "0.8" ron = { version = "0.8.0", features = ["integer128"] } diff --git a/src/resource.rs b/src/resource.rs index a841daf..658bdb4 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -162,7 +162,7 @@ where #[cfg(test)] mod tests { use bevy::reflect::TypePath; - use bevy_prng::{ChaCha8Rng, ChaCha12Rng}; + use bevy_prng::{ChaCha8Rng, ChaCha12Rng, WyRand}; use super::*; @@ -196,7 +196,7 @@ mod tests { fn forking_as() { let mut rng1 = GlobalEntropy::::default(); - let rng2 = rng1.fork_as::(); + let rng2 = rng1.fork_as::(); let rng1 = format!("{:?}", rng1); let rng2 = format!("{:?}", rng2); diff --git a/tests/determinism.rs b/tests/determinism.rs index aa56a2d..76554d4 100644 --- a/tests/determinism.rs +++ b/tests/determinism.rs @@ -1,10 +1,11 @@ #![allow(clippy::type_complexity)] use bevy::prelude::*; -use bevy_prng::ChaCha8Rng; +use bevy_prng::{ChaCha8Rng, WyRand, ChaCha12Rng}; use bevy_rand::prelude::*; use rand::prelude::Rng; +use rand_core::RngCore; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; @@ -23,6 +24,9 @@ struct SourceC; #[derive(Component)] struct SourceD; +#[derive(Component)] +struct SourceE; + fn random_output_a(mut q_source: Query<&mut EntropyComponent, With>) { let mut rng = q_source.single_mut(); @@ -49,24 +53,40 @@ fn random_output_c(mut q_source: Query<&mut EntropyComponent, With, With>) { +fn random_output_d(mut q_source: Query<&mut EntropyComponent, With>) { let mut rng = q_source.single_mut(); assert_eq!( rng.gen::<(u16, u16)>(), - (61569, 26940), + (41421, 7891), "SourceD does not match expected output" ); } +fn random_output_e(mut q_source: Query<&mut EntropyComponent, With>) { + let mut rng = q_source.single_mut(); + + let mut bytes = [0u8; 8]; + + rng.fill_bytes(bytes.as_mut()); + + assert_eq!( + &bytes, + &[195, 159, 73, 157, 39, 99, 104, 111], + "SourceE does not match expected output" + ); +} + fn setup_sources(mut commands: Commands, mut rng: ResMut>) { - commands.spawn((SourceA, rng.fork_as::())); + commands.spawn((SourceA, rng.fork_rng())); commands.spawn((SourceB, rng.fork_rng())); commands.spawn((SourceC, rng.fork_rng())); - commands.spawn((SourceD, rng.fork_rng())); + commands.spawn((SourceD, rng.fork_as::())); + + commands.spawn((SourceE, rng.fork_as::())); } /// Entities having their own sources side-steps issues with parallel execution and scheduling @@ -91,6 +111,7 @@ fn test_parallel_determinism() { random_output_b, random_output_c, random_output_d, + random_output_e, ), ) .run(); From 7e7f13daf5ac45857fcda4209f0740d9f8d5978e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Rica=20Pais=20da=20Silva?= Date: Sat, 21 Oct 2023 11:03:27 +0200 Subject: [PATCH 09/11] feat: Simplified dependency/feature options --- .github/workflows/ci.yml | 4 ++-- Cargo.toml | 9 +++++++++ README.md | 33 ++++++++++++++++++++++++++------- bevy_prng/Cargo.toml | 5 +++++ src/prelude.rs | 19 +++++++++++++++++++ 5 files changed, 61 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b5cf34..64feea9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,7 +70,7 @@ jobs: rustup override set nightly cargo miri setup - name: Test with Miri - run: cargo miri test --all-features + run: cargo miri test env: # -Zrandomize-layout makes sure we dont rely on the layout of anything that might change RUSTFLAGS: -Zrandomize-layout @@ -102,4 +102,4 @@ jobs: run: rustup update ${{ env.MSRV }} --no-self-update && rustup default ${{ env.MSRV }} - name: Run cargo check id: check - run: cargo check --all-features + run: cargo check diff --git a/Cargo.toml b/Cargo.toml index 6bf9e8d..dc887cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,10 @@ rust-version = "1.70.0" default = ["serialize", "thread_local_entropy"] thread_local_entropy = ["dep:rand_chacha"] serialize = ["dep:serde", "rand_core/serde1"] +rand_chacha = ["bevy_prng/rand_chacha"] +rand_pcg = ["bevy_prng/rand_pcg"] +rand_xoshiro = ["bevy_prng/rand_xoshiro"] +wyrand = ["bevy_prng/wyrand"] [workspace] members = ["bevy_prng"] @@ -51,3 +55,8 @@ getrandom = { version = "0.2", features = ["js"] } [[example]] name = "turn_based_game" path = "examples/turn_based_game.rs" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] +rustc-args = ["--cfg", "docsrs"] diff --git a/README.md b/README.md index 32fe4ed..a64505a 100644 --- a/README.md +++ b/README.md @@ -54,12 +54,19 @@ Bevy Rand provides forking via `ForkableRng`/`ForkableAsRng`/`ForkableInnerRng` ## Using Bevy Rand -Usage of Bevy Rand can range from very simple to quite complex use-cases, all depending on whether one cares about deterministic output or not. First, add `bevy_rand`,`bevy_prng`, and either `rand_core` or `rand` to your `Cargo.toml` to bring in both the components and the PRNGs you want to use, along with the various traits needed to use the RNGs. To select a given algorithm type with `bevy_prng`, enable the feature representing the newtypes from the `rand_*` crate you want to use. +Usage of Bevy Rand can range from very simple to quite complex use-cases, all depending on whether one cares about deterministic output or not. First, add `bevy_rand`, and either `rand_core` or `rand` to your `Cargo.toml` to bring in both the components and the PRNGs you want to use, along with the various traits needed to use the RNGs. To select a given algorithm type with `bevy_rand`, enable the feature representing the algorithm `rand_*` crate you want to use. This will then give you access to the PRNG structs via the prelude. Alternatively, you can use `bevy_prng` directly to get the newtyped structs with the same feature flags. However, using the algorithm crates like `rand_chacha` directly will not work as these don't implement the necessary traits to support bevy's reflection. The examples below use `bevy_prng` directly for purposes of clarity. +#### `bevy_rand` feature activation ```toml rand_core = "0.6" -bevy_rand = "0.3" -bevy_prng = { version = "0.1", features = ["rand_chacha"] } +bevy_rand = { version = "0.4", features = ["rand_chacha"] } +``` + +#### `bevy_prng` feature activation +```toml +rand_core = "0.6" +bevy_rand = "0.4" +bevy_prng = { version = "0.2", features = ["rand_chacha"] } ``` ### Registering a PRNG for use with Bevy Rand @@ -153,12 +160,20 @@ The examples provided as integration tests in this repo demonstrate the two diff ## Selecting and using PRNG Algorithms -All supported PRNGs and compatible structs are provided by `bevy_prng`, so the easiest way to work with `bevy_rand` is to import the necessary algorithm from `bevy_prng`. Simply activate the relevant features in `bevy_prng` to pull in the PRNG algorithm you want to use, and then import them like so: +All supported PRNGs and compatible structs are provided by the `bevy_prng` crate. Simply activate the relevant features in `bevy_rand`/`bevy_prng` to pull in the PRNG algorithm you want to use, and then import them like so: ```toml -bevy_prng = { version = "0.1", features = ["rand_chacha", "wyrand"] } +bevy_rand = { version = "0.4", features = ["rand_chacha", "wyrand"] } +``` +```rust ignore +use bevy::prelude::*; +use bevy_rand::prelude::{ChaCha8Rng, WyRand}; +``` +or +```toml +bevy_rand = "0.4" +bevy_prng = { version = "0.2", features = ["rand_chacha", "wyrand"] } ``` - ```rust ignore use bevy::prelude::*; use bevy_rand::prelude::*; @@ -169,12 +184,16 @@ Using PRNGs directly from the `rand_*` crates is not possible without newtyping, As a whole, which algorithm should be used/selected is dependent on a range of factors. Cryptographically Secure PRNGs (CSPRNGs) produce very hard to predict output (very high quality entropy), but in general are slow. The ChaCha algorithm can be sped up by using versions with less rounds (iterations of the algorithm), but this in turn reduces the quality of the output (making it easier to predict). However, `ChaCha8Rng` is still far stronger than what is feasible to be attacked, and is considerably faster as a source of entropy than the full `ChaCha20Rng`. `rand` uses `ChaCha12Rng` as a balance between security/quality of output and speed for its `StdRng`. CSPRNGs are important for cases when you _really_ don't want your output to be predictable and you need that extra level of assurance, such as doing any cryptography/authentication/security tasks. -If that extra level of security is not necessary, but there is still need for extra speed while maintaining good enough randomness, other PRNG algorithms exist for this purpose. These algorithms still try to output as high quality entropy as possible, but the level of entropy is not enough for cryptographic purposes. These algorithms should **never be used in situations that demand security**. Algorithms like `WyRand` and `Xoshiro256StarStar` are tuned for maximum throughput, while still possessing _good enough_ entropy for use as a source of randomness for non-security purposes. It still matters that the output is not predictable, but not to the same extent as CSPRNGs are required to be. +If that extra level of security is not necessary, but there is still need for extra speed while maintaining good enough randomness, other PRNG algorithms exist for this purpose. These algorithms still try to output as high quality entropy as possible, but the level of entropy is not enough for cryptographic purposes. These algorithms should **never be used in situations that demand security**. Algorithms like `WyRand` and `Xoshiro256StarStar` are tuned for maximum throughput, while still possessing _good enough_ entropy for use as a source of randomness for non-security purposes. It still matters that the output is not predictable, but not to the same extent as CSPRNGs are required to be. PRNGs like `WyRand` also have small state sizes, which makes them take less memory per instance compared to CSPRNGs like `ChaCha8Rng`. ## Features - **`thread_local_entropy`** - Enables `ThreadLocalEntropy`, overriding `SeedableRng::from_entropy` implementations to make use of thread local entropy sources for faster PRNG initialisation. Enabled by default. - **`serialize`** - Enables `Serialize` and `Deserialize` derives. Enabled by default. +- **`rand_chacha`** - This enables the exporting of newtyped `ChaCha*Rng` structs, for those that want/need to use a CSPRNG level source. +- **`rand_pcg`** - This enables the exporting of newtyped `Pcg*` structs from `rand_pcg`. +- **`rand_xoshiro`** - This enables the exporting of newtyped `Xoshiro*` structs from `rand_xoshiro`. It also reexports `Seed512` so to allow setting up `Xoshiro512StarStar` and so forth without the need to pull in `rand_xoshiro` explicitly. +- **`wyrand`** - This enables the exporting of newtyped `WyRand` from `wyrand`, the same algorithm in use within `fastrand`/`turborand`. ## Supported Versions & MSRV diff --git a/bevy_prng/Cargo.toml b/bevy_prng/Cargo.toml index 1d985cb..6b37fdb 100644 --- a/bevy_prng/Cargo.toml +++ b/bevy_prng/Cargo.toml @@ -31,3 +31,8 @@ rand_chacha = { version = "0.3", optional = true } wyrand = { version = "0.1", optional = true } rand_pcg = { version = "0.3", optional = true } rand_xoshiro = { version = "0.6", optional = true } + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] +rustc-args = ["--cfg", "docsrs"] diff --git a/src/prelude.rs b/src/prelude.rs index 4482719..58a9c7f 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -2,3 +2,22 @@ pub use crate::component::EntropyComponent; pub use crate::plugin::EntropyPlugin; pub use crate::resource::GlobalEntropy; pub use crate::traits::{ForkableAsRng, ForkableInnerRng, ForkableRng}; +#[cfg(feature = "wyrand")] +#[cfg_attr(docsrs, doc(cfg(feature = "wyrand")))] +pub use bevy_prng::WyRand; + +#[cfg(feature = "rand_chacha")] +#[cfg_attr(docsrs, doc(cfg(feature = "rand_chacha")))] +pub use bevy_prng::{ChaCha12Rng, ChaCha20Rng, ChaCha8Rng}; + +#[cfg(feature = "rand_pcg")] +#[cfg_attr(docsrs, doc(cfg(feature = "rand_pcg")))] +pub use bevy_prng::{Pcg32, Pcg64, Pcg64Mcg}; + +#[cfg(feature = "rand_xoshiro")] +#[cfg_attr(docsrs, doc(cfg(feature = "rand_xoshiro")))] +pub use bevy_prng::{ + Xoroshiro128Plus, Xoroshiro128PlusPlus, Xoroshiro128StarStar, Xoroshiro64Star, + Xoroshiro64StarStar, Xoshiro128Plus, Xoshiro128PlusPlus, Xoshiro128StarStar, Xoshiro256Plus, + Xoshiro256PlusPlus, Xoshiro256StarStar, Xoshiro512Plus, Xoshiro512PlusPlus, Xoshiro512StarStar, +}; From 0fad5555cb8fe5fe5b786840244864ca808b047c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Rica=20Pais=20da=20Silva?= Date: Mon, 23 Oct 2023 15:26:48 +0200 Subject: [PATCH 10/11] chore: Update readme on deprecations, migrations, and latest bevy commit --- Cargo.toml | 2 +- MIGRATIONS.md | 21 +++++++++++++++++++++ README.md | 22 +++------------------- bevy_prng/Cargo.toml | 2 +- 4 files changed, 26 insertions(+), 21 deletions(-) create mode 100644 MIGRATIONS.md diff --git a/Cargo.toml b/Cargo.toml index dc887cd..7ad66ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ members = ["bevy_prng"] [dependencies] # bevy -bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "1258ceb62cd8acb61f031dce128c2e04ee058538", version = "0.12.0-dev", default-features = false } +bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "51c70bc98cd9c71d8e55a4656f22d0229a0ef06e", version = "0.12.0-dev", default-features = false } bevy_prng = { path = "bevy_prng", version = "0.2" } # others diff --git a/MIGRATIONS.md b/MIGRATIONS.md new file mode 100644 index 0000000..bf19ff3 --- /dev/null +++ b/MIGRATIONS.md @@ -0,0 +1,21 @@ +# Migration Notes + +## Migrating from v0.2 to v0.3 + +As v0.3 is a breaking change to v0.2, the process to migrate over is fairly simple. The rand algorithm crates can no longer be used directly, but they can be swapped wholesale with `bevy_prng` instead. So the following `Cargo.toml` changes: + +```diff +- rand_chacha = { version = "0.3", features = ["serde1"] } ++ bevy_prng = { version = "0.1", features = ["rand_chacha"] } +``` + +allows then you to swap your import like so, which should then plug straight into existing `bevy_rand` usage seamlessly: + +```diff +use bevy::prelude::*; +use bevy_rand::prelude::*; +- use rand_chacha::ChaCha8Rng; ++ use bevy_prng::ChaCha8Rng; +``` + +This **will** change the type path and the serialization format for the PRNGs, but currently, moving between different bevy versions has this problem as well as there's currently no means to migrate serialized formats from one version to another yet. The rationale for this change is to enable stable `TypePath` that is being imposed by bevy's reflection system, so that future compiler changes won't break things unexpectedly as `std::any::type_name` has no stability guarantees. Going forward, this should resolve any stability problems `bevy_rand` might have and be able to hook into any migration tool `bevy` might offer for when scene formats change/update. diff --git a/README.md b/README.md index a64505a..6462960 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Bevy Rand operates around a global entropy source provided as a resource, and th If cloning creates a second instance that shares the same state as the original, forking derives a new state from the original, leaving the original 'changed' and the new instance with a randomised seed. Forking RNG instances from a global source is a way to ensure that one seed produces many deterministic states, while making it difficult to predict outputs from many sources and also ensuring no one source shares the same state either with the original or with each other. -Bevy Rand provides forking via `ForkableRng`/`ForkableAsRng`/`ForkableInnerRng` traits, allowing one to easily fork with just a simple `.fork_rng()` method call, making it straightforward to use. There's also `From` implementations, but from v0.4 onwards, these are considered deprecated and will likely be removed/changed in a future version. +Bevy Rand provides forking via `ForkableRng`/`ForkableAsRng`/`ForkableInnerRng` traits, allowing one to easily fork with just a simple `.fork_rng()` method call, making it straightforward to use. There's also `From` implementations, **but from v0.4 onwards, these are considered deprecated and will likely be removed/changed in a future version**. ## Using Bevy Rand @@ -205,25 +205,9 @@ If that extra level of security is not necessary, but there is still need for ex | v0.11 | v0.2, v0.3 | | v0.10 | v0.1 | -## Migrating from v0.2 to v0.3 +## Migrations -As v0.3 is a breaking change to v0.2, the process to migrate over is fairly simple. The rand algorithm crates can no longer be used directly, but they can be swapped wholesale with `bevy_prng` instead. So the following `Cargo.toml` changes: - -```diff -- rand_chacha = { version = "0.3", features = ["serde1"] } -+ bevy_prng = { version = "0.1", features = ["rand_chacha"] } -``` - -allows then you to swap your import like so, which should then plug straight into existing `bevy_rand` usage seamlessly: - -```diff -use bevy::prelude::*; -use bevy_rand::prelude::*; -- use rand_chacha::ChaCha8Rng; -+ use bevy_prng::ChaCha8Rng; -``` - -This **will** change the type path and the serialization format for the PRNGs, but currently, moving between different bevy versions has this problem as well as there's currently no means to migrate serialized formats from one version to another yet. The rationale for this change is to enable stable `TypePath` that is being imposed by bevy's reflection system, so that future compiler changes won't break things unexpectedly as `std::any::type_name` has no stability guarantees. Going forward, this should resolve any stability problems `bevy_rand` might have and be able to hook into any migration tool `bevy` might offer for when scene formats change/update. +Notes on migrating between versions can be found [here](MIGRATIONS.md). ## License diff --git a/bevy_prng/Cargo.toml b/bevy_prng/Cargo.toml index 6b37fdb..b057b41 100644 --- a/bevy_prng/Cargo.toml +++ b/bevy_prng/Cargo.toml @@ -24,7 +24,7 @@ serialize = [ ] [dependencies] -bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "1258ceb62cd8acb61f031dce128c2e04ee058538", version = "0.12.0-dev", default-features = false } +bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "51c70bc98cd9c71d8e55a4656f22d0229a0ef06e", version = "0.12.0-dev", default-features = false } rand_core = { version = "0.6", features = ["std"] } serde = { version = "1.0", features = ["derive"], optional = true } rand_chacha = { version = "0.3", optional = true } From 113ce38bf1dfae1239ae6088f820d8365e130581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Rica=20Pais=20da=20Silva?= Date: Sat, 4 Nov 2023 19:13:28 +0100 Subject: [PATCH 11/11] chore: update to latest bevy version --- Cargo.toml | 2 +- bevy_prng/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7ad66ce..84488d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ members = ["bevy_prng"] [dependencies] # bevy -bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "51c70bc98cd9c71d8e55a4656f22d0229a0ef06e", version = "0.12.0-dev", default-features = false } +bevy = { version = "0.12.0", default-features = false } bevy_prng = { path = "bevy_prng", version = "0.2" } # others diff --git a/bevy_prng/Cargo.toml b/bevy_prng/Cargo.toml index b057b41..2b08f16 100644 --- a/bevy_prng/Cargo.toml +++ b/bevy_prng/Cargo.toml @@ -24,7 +24,7 @@ serialize = [ ] [dependencies] -bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "51c70bc98cd9c71d8e55a4656f22d0229a0ef06e", version = "0.12.0-dev", default-features = false } +bevy = { version = "0.12.0", default-features = false } rand_core = { version = "0.6", features = ["std"] } serde = { version = "1.0", features = ["derive"], optional = true } rand_chacha = { version = "0.3", optional = true }