Skip to content

Commit

Permalink
feat: Observer driven seeding + forking (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bluefinger authored Nov 12, 2024
1 parent bf719b7 commit ee28a64
Show file tree
Hide file tree
Showing 26 changed files with 607 additions and 237 deletions.
10 changes: 7 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ version = "0.8.0"
rust-version = "1.76.0"

[workspace.dependencies]
bevy = { version = "0.15.0-rc.3", default-features = false }
bevy_app = { version = "0.15.0-rc.3" }
bevy_ecs = { version = "0.15.0-rc.3" }
bevy_reflect = { version = "0.15.0-rc.3", default-features = false }
serde = "1"
serde_derive = "1"
rand_core = { version = "0.6", features = ["std"] }
Expand All @@ -35,6 +37,7 @@ rust-version = { workspace = true }

[features]
default = ["serialize", "thread_local_entropy"]
experimental = []
thread_local_entropy = ["dep:rand_chacha"]
serialize = ["dep:serde", "dep:serde_derive", "rand_core/serde1"]
rand_chacha = ["bevy_prng/rand_chacha"]
Expand All @@ -43,8 +46,9 @@ rand_xoshiro = ["bevy_prng/rand_xoshiro"]
wyrand = ["bevy_prng/wyrand"]

[dependencies]
# bevy
bevy.workspace = true
bevy_app.workspace = true
bevy_ecs.workspace = true
bevy_reflect.workspace = true
bevy_prng = { path = "bevy_prng", version = "0.8" }

# others
Expand Down
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ The summary of what RNG algorithm to choose is: pick `wyrand` for almost all cas
Before a PRNG can be used via `GlobalEntropy` or `EntropyComponent`, it must be registered via the plugin.

```rust
use bevy::prelude::*;
use bevy_ecs::prelude::*;
use bevy_app::App;
use bevy_prng::WyRand;
use bevy_rand::prelude::EntropyPlugin;
use rand_core::RngCore;
Expand All @@ -54,7 +55,7 @@ fn main() {
At the simplest case, using `GlobalEntropy` directly for all random number generation, though this does limit how well systems using `GlobalEntropy` can be parallelised. All systems that access `GlobalEntropy` will run serially to each other.

```rust
use bevy::prelude::ResMut;
use bevy_ecs::prelude::ResMut;
use bevy_prng::WyRand;
use bevy_rand::prelude::GlobalEntropy;
use rand_core::RngCore;
Expand All @@ -69,7 +70,7 @@ fn print_random_value(mut rng: ResMut<GlobalEntropy<WyRand>>) {
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::*;
use bevy_ecs::prelude::*;
use bevy_prng::WyRand;
use bevy_rand::prelude::{GlobalEntropy, ForkableRng};

Expand All @@ -88,7 +89,7 @@ fn setup_source(mut commands: Commands, mut global: ResMut<GlobalEntropy<WyRand>
`EntropyComponent`s can be seeded/forked from other `EntropyComponent`s as well.

```rust
use bevy::prelude::*;
use bevy_ecs::prelude::*;
use bevy_prng::WyRand;
use bevy_rand::prelude::{EntropyComponent, ForkableRng};

Expand Down Expand Up @@ -121,14 +122,16 @@ fn setup_npc_from_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 exports a remote-reflected version of `Seed512` so to allow setting up `Xoshiro512StarStar` and so forth.
- **`wyrand`** - This enables the exporting of newtyped `WyRand` from `wyrand`, the same algorithm in use within `fastrand`/`turborand`.
- **`experimental`** - This enables any unstable/experimental features for `bevy_rand`. Currently, this will expose utilities for making use of observers for reseeding sources.

## Supported Versions & MSRV

`bevy_rand` uses the same MSRV as `bevy`.

| `bevy` | `bevy_rand` |
| ------ | ------------ |
| v0.14 | v0.7 - v0.8 |
| v0.15 | v0.8 |
| v0.14 | v0.7 |
| v0.13 | v0.5 - v0.6 |
| v0.12 | v0.4 |
| v0.11 | v0.2 - v0.3 |
Expand Down
2 changes: 1 addition & 1 deletion bevy_prng/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ serialize = [
]

[dependencies]
bevy.workspace = true
bevy_reflect.workspace = true
rand_core.workspace = true
serde = { workspace = true, optional = true }
serde_derive = { workspace = true, optional = true }
Expand Down
4 changes: 2 additions & 2 deletions bevy_prng/src/chacha.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::{newtype::newtype_prng, SeedableEntropySource};

use bevy::prelude::{Reflect, ReflectFromReflect};
use bevy_reflect::{Reflect, ReflectFromReflect};
use rand_core::{RngCore, SeedableRng};

#[cfg(feature = "serialize")]
use bevy::prelude::{ReflectDeserialize, ReflectSerialize};
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};

newtype_prng!(
ChaCha8Rng,
Expand Down
23 changes: 5 additions & 18 deletions bevy_prng/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ mod xoshiro;

use std::fmt::Debug;

use bevy::{
prelude::{FromReflect, Reflect},
reflect::{GetTypeRegistration, TypePath, Typed},
};
use bevy_reflect::{FromReflect, Reflectable, Typed};
use rand_core::{RngCore, SeedableRng};
#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
Expand All @@ -49,11 +46,8 @@ pub trait SeedableEntropySource:
+ PartialEq
+ Sync
+ Send
+ Reflect
+ TypePath
+ FromReflect
+ GetTypeRegistration
+ Typed
+ Reflectable
+ Serialize
+ for<'a> Deserialize<'a>
+ private::SealedSeedable
Expand All @@ -71,10 +65,8 @@ pub trait EntropySeed:
+ Clone
+ Sync
+ Send
+ Reflect
+ TypePath
+ Reflectable
+ FromReflect
+ GetTypeRegistration
+ Serialize
+ for<'a> Deserialize<'a>
{
Expand All @@ -89,10 +81,8 @@ impl<
+ Clone
+ Sync
+ Send
+ Reflect
+ TypePath
+ Reflectable
+ FromReflect
+ GetTypeRegistration
+ Serialize
+ for<'a> Deserialize<'a>,
> EntropySeed for T
Expand All @@ -109,11 +99,8 @@ pub trait SeedableEntropySource:
+ Debug
+ PartialEq
+ AsMut<[u8]>
+ Reflect
+ TypePath
+ Reflectable
+ FromReflect
+ GetTypeRegistration
+ Typed
+ Sync
+ Send
+ private::SealedSeedable
Expand Down
3 changes: 3 additions & 0 deletions bevy_prng/src/newtype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ macro_rules! newtype_prng {
($newtype:tt, $rng:ty, $doc:tt, $feature:tt) => {
#[doc = $doc]
#[derive(Debug, Clone, PartialEq, Reflect)]
#[reflect(opaque)]
#[cfg_attr(
feature = "serialize",
derive(::serde_derive::Serialize, ::serde_derive::Deserialize)
Expand Down Expand Up @@ -75,6 +76,7 @@ macro_rules! newtype_prng {
};
}

#[cfg(feature = "rand_xoshiro")]
macro_rules! newtype_prng_remote {
($newtype:tt, $rng:ty, $seed:ty, $doc:tt, $feature:tt) => {
#[doc = $doc]
Expand Down Expand Up @@ -153,4 +155,5 @@ macro_rules! newtype_prng_remote {
}

pub(crate) use newtype_prng;
#[cfg(feature = "rand_xoshiro")]
pub(crate) use newtype_prng_remote;
4 changes: 2 additions & 2 deletions bevy_prng/src/pcg.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::{newtype::newtype_prng, SeedableEntropySource};

use bevy::prelude::{Reflect, ReflectFromReflect};
use bevy_reflect::{Reflect, ReflectFromReflect};
use rand_core::{RngCore, SeedableRng};

#[cfg(feature = "serialize")]
use bevy::prelude::{ReflectDeserialize, ReflectSerialize};
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};

newtype_prng!(
Pcg32,
Expand Down
4 changes: 2 additions & 2 deletions bevy_prng/src/wyrand.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::{newtype::newtype_prng, SeedableEntropySource};

use bevy::prelude::{Reflect, ReflectFromReflect};
use bevy_reflect::{Reflect, ReflectFromReflect};
use rand_core::{RngCore, SeedableRng};

#[cfg(feature = "serialize")]
use bevy::prelude::{ReflectDeserialize, ReflectSerialize};
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};

newtype_prng!(
WyRand,
Expand Down
7 changes: 2 additions & 5 deletions bevy_prng/src/xoshiro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@ use crate::{
SeedableEntropySource,
};

use bevy::{
prelude::{Reflect, ReflectDefault, ReflectFromReflect},
reflect::reflect_remote,
};
use bevy_reflect::{reflect_remote, std_traits::ReflectDefault, Reflect, ReflectFromReflect};
use rand_core::{RngCore, SeedableRng};

#[cfg(feature = "serialize")]
use bevy::prelude::{ReflectDeserialize, ReflectSerialize};
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};

/// Remote reflected version of [`rand_xoshiro::Seed512`], needed to support
/// proper reflection for the 512 bit variants of the Xoshiro PRNG.
Expand Down
3 changes: 2 additions & 1 deletion examples/turn_based_game.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![allow(clippy::type_complexity)]

use bevy::prelude::*;
use bevy_app::prelude::*;
use bevy_ecs::prelude::*;
use bevy_prng::ChaCha8Rng;
use bevy_rand::prelude::{EntropyComponent, EntropyPlugin, ForkableRng, GlobalEntropy};
use rand::prelude::{IteratorRandom, Rng};
Expand Down
17 changes: 9 additions & 8 deletions src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ use crate::{
ForkableRng, ForkableSeed,
},
};
use bevy::prelude::{Component, Reflect, ReflectComponent, ReflectFromReflect};
use bevy_ecs::prelude::{Component, ReflectComponent};
use bevy_prng::SeedableEntropySource;
use bevy_reflect::{Reflect, ReflectFromReflect};
use rand_core::{RngCore, SeedableRng};

#[cfg(feature = "thread_local_entropy")]
use crate::thread_local_entropy::ThreadLocalEntropy;

#[cfg(feature = "serialize")]
use bevy::prelude::{ReflectDeserialize, ReflectSerialize};
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};

#[cfg(feature = "serialize")]
use serde::Deserialize;
Expand All @@ -33,7 +34,7 @@ use serde::Deserialize;
///
/// Randomised Component:
/// ```
/// use bevy::prelude::*;
/// use bevy_ecs::prelude::*;
/// use bevy_prng::WyRand;
/// use bevy_rand::prelude::EntropyComponent;
///
Expand All @@ -51,7 +52,7 @@ use serde::Deserialize;
///
/// Seeded from a resource:
/// ```
/// use bevy::prelude::*;
/// use bevy_ecs::prelude::*;
/// use bevy_prng::ChaCha8Rng;
/// use bevy_rand::prelude::{GlobalEntropy, ForkableRng};
///
Expand All @@ -69,7 +70,7 @@ use serde::Deserialize;
///
/// Seeded from a component:
/// ```
/// use bevy::prelude::*;
/// use bevy_ecs::prelude::*;
/// use bevy_prng::WyRand;
/// use bevy_rand::prelude::{EntropyComponent, ForkableRng};
///
Expand Down Expand Up @@ -233,8 +234,8 @@ where

#[cfg(test)]
mod tests {
use bevy::reflect::TypePath;
use bevy_prng::{ChaCha12Rng, ChaCha8Rng};
use bevy_reflect::TypePath;

use super::*;

Expand Down Expand Up @@ -293,7 +294,7 @@ mod tests {
#[cfg(feature = "serialize")]
#[test]
fn rng_untyped_serialization() {
use bevy::reflect::{
use bevy_reflect::{
serde::{ReflectDeserializer, ReflectSerializer},
FromReflect, TypeRegistry,
};
Expand Down Expand Up @@ -341,7 +342,7 @@ mod tests {
#[cfg(feature = "serialize")]
#[test]
fn rng_typed_serialization() {
use bevy::reflect::{
use bevy_reflect::{
serde::{TypedReflectDeserializer, TypedReflectSerializer},
FromReflect, GetTypeRegistration, TypeRegistry,
};
Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(clippy::type_complexity)]
#![warn(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, allow(unused_attributes))]
Expand All @@ -6,6 +7,9 @@

/// Components for integrating [`RngCore`] PRNGs into bevy. Must be newtyped to support [`Reflect`].
pub mod component;
#[cfg(feature = "experimental")]
/// Utility observers for handling seeding between parent/child entropy sources
pub mod observers;
/// Plugin for integrating [`RngCore`] PRNGs into bevy. Must be newtyped to support [`Reflect`].
pub mod plugin;
/// Prelude for providing all necessary types for easy use.
Expand Down
Loading

0 comments on commit ee28a64

Please sign in to comment.