Skip to content

Commit

Permalink
feat: Yeet Resources, make it all entities
Browse files Browse the repository at this point in the history
  • Loading branch information
Bluefinger committed Dec 15, 2024
1 parent 0c4f973 commit 2d1d52d
Show file tree
Hide file tree
Showing 14 changed files with 84 additions and 69 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,11 @@ fn example_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_ecs::prelude::ResMut;
use bevy_prng::WyRand;
use bevy_rand::prelude::GlobalEntropy;
use rand_core::RngCore;

fn print_random_value(mut rng: ResMut<GlobalEntropy<WyRand>>) {
fn print_random_value(mut rng: GlobalEntropy<WyRand>) {
println!("Random value: {}", rng.next_u32());
}
```
Expand All @@ -79,7 +78,7 @@ use bevy_rand::prelude::{GlobalEntropy, ForkableRng};
#[derive(Component)]
struct Source;

fn setup_source(mut commands: Commands, mut global: ResMut<GlobalEntropy<WyRand>>) {
fn setup_source(mut commands: Commands, mut global: GlobalEntropy<WyRand>) {
commands
.spawn((
Source,
Expand Down
4 changes: 2 additions & 2 deletions examples/turn_based_game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fn main() {
.run();
}

fn setup_player(mut commands: Commands, mut rng: ResMut<GlobalEntropy<ChaCha8Rng>>) {
fn setup_player(mut commands: Commands, mut rng: GlobalEntropy<ChaCha8Rng>) {
commands.spawn((
Kind::Player,
Name("Player".into()),
Expand All @@ -73,7 +73,7 @@ fn setup_player(mut commands: Commands, mut rng: ResMut<GlobalEntropy<ChaCha8Rng
));
}

fn setup_enemies(mut commands: Commands, mut rng: ResMut<GlobalEntropy<ChaCha8Rng>>) {
fn setup_enemies(mut commands: Commands, mut rng: GlobalEntropy<ChaCha8Rng>) {
for i in 1..=2 {
commands.spawn((
Kind::Enemy,
Expand Down
4 changes: 2 additions & 2 deletions src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use serde::Deserialize;
/// ## Creating new [`Entropy`]s.
///
/// You can creates a new [`Entropy`] directly from anything that implements
/// [`RngCore`] or provides a mut reference to [`RngCore`], such as [`ResMut`] or a
/// [`RngCore`] or provides a mut reference to [`RngCore`], such as a
/// [`Component`], or from a [`RngCore`] source directly.
///
/// ## Examples
Expand Down Expand Up @@ -59,7 +59,7 @@ use serde::Deserialize;
/// #[derive(Component)]
/// struct Source;
///
/// fn setup_source(mut commands: Commands, mut global: ResMut<GlobalEntropy<ChaCha8Rng>>) {
/// fn setup_source(mut commands: Commands, mut global: GlobalEntropy<ChaCha8Rng>) {
/// commands
/// .spawn((
/// Source,
Expand Down
20 changes: 20 additions & 0 deletions src/global.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use bevy_ecs::{component::Component, entity::Entity, query::With, system::Single};

use crate::{prelude::Entropy, seed::RngSeed};

/// A marker component to signify a global source. Warning: there should only be **one** entity per
/// PRNG type that qualifies as the `Global` source.
#[derive(Debug, Component)]
pub struct Global;

/// A helper query to yield the [`Global`] source for a given [`bevy_prng::EntropySource`]. This returns the
/// [`Entropy`] component to generate new random numbers from.
pub type GlobalEntropy<'w, T> = Single<'w, &'static mut Entropy<T>, With<Global>>;

/// A helper query to yield the [`Global`] source for a given [`EntropySource`]. This returns the
/// [`RngSeed`] component to allow inspection to the initial seed for the source.
pub type GlobalSeed<'w, T> = Single<'w, &'static RngSeed<T>, With<Global>>;

/// A helper query to yield the [`Global`] source for a given [`EntropySource`]. This returns the
/// [`Entity`] id to modify the source with via commands.
pub type GlobalSource<'w, T> = Single<'w, Entity, (With<RngSeed<T>>, With<Global>)>;
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@

/// Components for integrating [`RngCore`] PRNGs into bevy. Must be newtyped to support [`Reflect`].
pub mod component;
/// Global [`crate::component::Entropy`] sources, with query helpers.
pub mod global;
#[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.
pub mod prelude;
/// Resource for integrating [`RngCore`] PRNGs into bevy. Must be newtyped to support [`Reflect`].
pub mod resource;
/// Seed Resource for seeding [`crate::resource::GlobalEntropy`].
pub mod seed;
#[cfg(feature = "thread_local_entropy")]
Expand Down
4 changes: 2 additions & 2 deletions src/observers.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::marker::PhantomData;

use bevy_ecs::{
prelude::{Commands, Component, Entity, Event, OnInsert, ResMut, Trigger, With},
prelude::{Commands, Component, Entity, Event, OnInsert, Trigger, With},
query::Without,
system::{Populated, Single},
};
Expand Down Expand Up @@ -118,7 +118,7 @@ where
/// Observer System for pulling in a new seed from a GlobalEntropy source
pub fn seed_from_global<Rng: EntropySource>(
trigger: Trigger<SeedFromGlobal<Rng>>,
mut source: ResMut<GlobalEntropy<Rng>>,
mut source: GlobalEntropy<Rng>,
mut commands: Commands,
) where
Rng::Seed: Send + Sync + Clone,
Expand Down
17 changes: 9 additions & 8 deletions src/plugin.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
#[cfg(feature = "experimental")]
use std::marker::PhantomData;

use crate::{component::Entropy, resource::GlobalEntropy, seed::RngSeed};
use crate::{component::Entropy, global::Global, seed::RngSeed, traits::SeedSource};
use bevy_app::{App, Plugin};
#[cfg(feature = "experimental")]
use bevy_ecs::prelude::Component;
use bevy_prng::{EntropySeed, EntropySource};
use rand_core::SeedableRng;

/// Plugin for integrating a PRNG that implements `RngCore` into
/// the bevy engine, registering types for a global resource and
Expand All @@ -29,7 +28,7 @@ use rand_core::SeedableRng;
/// .run();
/// }
///
/// fn print_random_value(mut rng: ResMut<GlobalEntropy<WyRand>>) {
/// fn print_random_value(mut rng: GlobalEntropy<WyRand>) {
/// println!("Random value: {}", rng.next_u32());
/// }
/// ```
Expand Down Expand Up @@ -71,19 +70,21 @@ where
R::Seed: EntropySeed,
{
fn build(&self, app: &mut App) {
app.register_type::<GlobalEntropy<R>>()
.register_type::<Entropy<R>>()
app.register_type::<Entropy<R>>()
.register_type::<R::Seed>();

app.world_mut().register_component_hooks::<RngSeed<R>>();

if let Some(seed) = self.seed.as_ref() {
app.insert_resource(GlobalEntropy::<R>::from_seed(seed.clone()));
app.world_mut().spawn((RngSeed::<R>::from_seed(seed.clone()), Global));
} else {
app.init_resource::<GlobalEntropy<R>>();
app.world_mut().spawn((RngSeed::<R>::from_entropy(), Global));
}

#[cfg(feature = "experimental")]
app.add_observer(crate::observers::seed_from_global::<R>)
.add_observer(crate::observers::reseed::<R>);
app.world_mut().register_component_hooks::<RngSeed<R>>();

}
}

Expand Down
2 changes: 1 addition & 1 deletion src/prelude.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pub use crate::component::Entropy;
pub use crate::plugin::EntropyPlugin;
pub use crate::resource::GlobalEntropy;
pub use crate::global::*;
pub use crate::seed::RngSeed;
pub use crate::traits::{
ForkableAsRng, ForkableAsSeed, ForkableInnerRng, ForkableInnerSeed, ForkableRng, ForkableSeed,
Expand Down
3 changes: 1 addition & 2 deletions src/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ use serde::{Deserialize, Serialize};
/// # Example
///
/// ```
/// use bevy_ecs::prelude::*;
/// use bevy_prng::ChaCha8Rng;
/// use bevy_rand::prelude::GlobalEntropy;
/// use rand_core::RngCore;
///
/// fn print_random_value(mut rng: ResMut<GlobalEntropy<ChaCha8Rng>>) {
/// fn print_random_value(mut rng: GlobalEntropy<ChaCha8Rng>) {
/// println!("Random value: {}", rng.next_u32());
/// }
/// ```
Expand Down
26 changes: 13 additions & 13 deletions src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bevy_prng::EntropySource;
use rand_core::{RngCore, SeedableRng};

/// Trait for implementing Forking behaviour for [`crate::component::EntropyComponent`] and [`crate::resource::GlobalEntropy`].
/// Trait for implementing Forking behaviour for [`crate::component::EntropyComponent`].
/// 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: EcsEntropy {
Expand All @@ -18,7 +18,7 @@ pub trait ForkableRng: EcsEntropy {
/// #[derive(Component)]
/// struct Source;
///
/// fn setup_source(mut commands: Commands, mut global: ResMut<GlobalEntropy<ChaCha8Rng>>) {
/// fn setup_source(mut commands: Commands, mut global: GlobalEntropy<ChaCha8Rng>) {
/// commands
/// .spawn((
/// Source,
Expand All @@ -31,7 +31,7 @@ pub trait ForkableRng: EcsEntropy {
}
}

/// Trait for implementing Forking behaviour for [`crate::component::EntropyComponent`] and [`crate::resource::GlobalEntropy`].
/// Trait for implementing Forking behaviour for [`crate::component::EntropyComponent`].
/// 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: EcsEntropy {
Expand All @@ -50,7 +50,7 @@ pub trait ForkableAsRng: EcsEntropy {
/// #[derive(Component)]
/// struct Source;
///
/// fn setup_source(mut commands: Commands, mut global: ResMut<GlobalEntropy<ChaCha12Rng>>) {
/// fn setup_source(mut commands: Commands, mut global: GlobalEntropy<ChaCha12Rng>) {
/// commands
/// .spawn((
/// Source,
Expand All @@ -63,7 +63,7 @@ pub trait ForkableAsRng: EcsEntropy {
}
}

/// Trait for implementing Forking behaviour for [`crate::component::EntropyComponent`] and [`crate::resource::GlobalEntropy`].
/// Trait for implementing Forking behaviour for [`crate::component::EntropyComponent`].
/// 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: EcsEntropy {
Expand All @@ -85,7 +85,7 @@ pub trait ForkableInnerRng: EcsEntropy {
/// println!("Random value: {}", source.next_u32());
/// }
///
/// fn access_source(mut global: ResMut<GlobalEntropy<ChaCha8Rng>>) {
/// fn access_source(mut global: GlobalEntropy<ChaCha8Rng>) {
/// let mut source = global.fork_inner();
///
/// do_random_action(&mut source);
Expand All @@ -96,7 +96,7 @@ pub trait ForkableInnerRng: EcsEntropy {
}
}

/// Trait for implementing forking behaviour for [`crate::component::EntropyComponent`] and [`crate::resource::GlobalEntropy`].
/// Trait for implementing forking behaviour for [`crate::component::EntropyComponent`].
/// 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 from an entropy source to a seed component.
pub trait ForkableSeed<S: EntropySource>: EcsEntropy
Expand All @@ -116,7 +116,7 @@ where
/// #[derive(Component)]
/// struct Source;
///
/// fn setup_source(mut commands: Commands, mut global: ResMut<GlobalEntropy<ChaCha8Rng>>) {
/// fn setup_source(mut commands: Commands, mut global: GlobalEntropy<ChaCha8Rng>) {
/// commands
/// .spawn((
/// Source,
Expand All @@ -133,7 +133,7 @@ where
}
}

/// Trait for implementing Forking behaviour for [`crate::component::EntropyComponent`] and [`crate::resource::GlobalEntropy`].
/// Trait for implementing Forking behaviour for [`crate::component::EntropyComponent`].
/// 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 from an entropy source to a seed component of a different
/// PRNG algorithm.
Expand All @@ -154,7 +154,7 @@ pub trait ForkableAsSeed<S: EntropySource>: EcsEntropy {
/// #[derive(Component)]
/// struct Source;
///
/// fn setup_source(mut commands: Commands, mut global: ResMut<GlobalEntropy<ChaCha12Rng>>) {
/// fn setup_source(mut commands: Commands, mut global: GlobalEntropy<ChaCha12Rng>) {
/// commands
/// .spawn((
/// Source,
Expand All @@ -174,7 +174,7 @@ pub trait ForkableAsSeed<S: EntropySource>: EcsEntropy {
}
}

/// Trait for implementing forking behaviour for [`crate::component::EntropyComponent`] and [`crate::resource::GlobalEntropy`].
/// Trait for implementing forking behaviour for [`crate::component::EntropyComponent`].
/// 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 from an entropy source to the RNG's seed type.
pub trait ForkableInnerSeed<S: EntropySource>: EcsEntropy
Expand All @@ -194,7 +194,7 @@ where
/// #[derive(Component)]
/// struct Source;
///
/// fn setup_source(mut commands: Commands, mut global: ResMut<GlobalEntropy<ChaCha8Rng>>) {
/// fn setup_source(mut commands: Commands, mut global: GlobalEntropy<ChaCha8Rng>) {
/// commands
/// .spawn((
/// Source,
Expand Down Expand Up @@ -251,7 +251,7 @@ where
}
}

/// A marker trait for [`crate::component::EntropyComponent`] and [`crate::resource::GlobalEntropy`].
/// A marker trait for [`crate::component::EntropyComponent`].
/// This is a sealed trait and cannot be consumed by downstream.
pub trait EcsEntropy: RngCore + SeedableRng + private::SealedSource {}

Expand Down
6 changes: 3 additions & 3 deletions tests/integration/determinism.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bevy_app::prelude::*;
use bevy_ecs::prelude::*;
use bevy_prng::{ChaCha12Rng, ChaCha8Rng, WyRand};
use bevy_rand::prelude::{Entropy, EntropyPlugin, ForkableAsRng, ForkableRng, GlobalEntropy};
use bevy_rand::{global::GlobalSeed, prelude::{Entropy, EntropyPlugin, ForkableAsRng, ForkableRng, GlobalEntropy}, traits::SeedSource};
use rand::prelude::Rng;

use rand_core::RngCore;
Expand Down Expand Up @@ -74,7 +74,7 @@ fn random_output_e(mut q_source: Query<&mut Entropy<WyRand>, With<SourceE>>) {
);
}

fn setup_sources(mut commands: Commands, mut rng: ResMut<GlobalEntropy<ChaCha8Rng>>) {
fn setup_sources(mut commands: Commands, mut rng: GlobalEntropy<ChaCha8Rng>) {
commands.spawn((SourceA, rng.fork_rng()));

commands.spawn((SourceB, rng.fork_rng()));
Expand All @@ -86,7 +86,7 @@ fn setup_sources(mut commands: Commands, mut rng: ResMut<GlobalEntropy<ChaCha8Rn
commands.spawn((SourceE, rng.fork_as::<WyRand>()));
}

fn read_global_seed(rng: Res<GlobalEntropy<ChaCha8Rng>>) {
fn read_global_seed(rng: GlobalSeed<ChaCha8Rng>) {
assert_eq!(rng.get_seed(), &[2; 32]);
}

Expand Down
Loading

0 comments on commit 2d1d52d

Please sign in to comment.