bevy_rand/plugin.rs
1use core::marker::PhantomData;
2
3use crate::{global::GlobalRng, seed::RngSeed, traits::SeedSource};
4use bevy_app::{App, Plugin};
5use bevy_prng::{EntropySeed, EntropySource};
6
7/// Plugin for integrating a PRNG that implements `Rng` into
8/// the bevy engine, registering types for a global resource and
9/// entropy components.
10///
11/// ```
12/// use bevy_app::prelude::*;
13/// use bevy_ecs::prelude::*;
14/// use bevy_prng::{ChaCha8Rng, WyRand};
15/// use bevy_rand::prelude::{EntropyPlugin, GlobalRng};
16/// use rand_core::Rng;
17///
18/// fn main() {
19/// App::new()
20/// .add_plugins((
21/// EntropyPlugin::<ChaCha8Rng>::default(),
22/// EntropyPlugin::<WyRand>::default()
23/// ))
24/// .add_systems(Update, print_random_value)
25/// .run();
26/// }
27///
28/// fn print_random_value(mut rng: Single<&mut WyRand, With<GlobalRng>>) {
29/// println!("Random value: {}", rng.next_u32());
30/// }
31/// ```
32pub struct EntropyPlugin<Rng: EntropySource + 'static> {
33 seed: Option<Rng::Seed>,
34}
35
36impl<Rng: EntropySource + 'static> EntropyPlugin<Rng> {
37 /// Creates a new plugin instance configured for randomised,
38 /// non-deterministic seeding of the global entropy resource.
39 #[inline]
40 #[must_use]
41 pub fn new() -> Self {
42 Self { seed: None }
43 }
44
45 /// Configures the plugin instance to have a set seed for the
46 /// global entropy resource.
47 #[inline]
48 pub fn with_seed(seed: Rng::Seed) -> Self {
49 Self { seed: Some(seed) }
50 }
51}
52
53impl<Rng: EntropySource + 'static> Default for EntropyPlugin<Rng> {
54 fn default() -> Self {
55 Self::new()
56 }
57}
58
59impl<Rng: EntropySource + 'static> Plugin for EntropyPlugin<Rng>
60where
61 Rng::Seed: EntropySeed,
62{
63 fn build(&self, app: &mut App) {
64 #[cfg(feature = "bevy_reflect")]
65 app.register_type::<Rng>()
66 .register_type::<RngSeed<Rng>>()
67 .register_type::<Rng::Seed>();
68
69 #[cfg(feature = "bevy_reflect")]
70 app.register_type_data::<Rng, bevy_prng::ReflectRemoteRng>();
71
72 let world = app.world_mut();
73
74 world.spawn((
75 self.seed
76 .clone()
77 .map_or_else(RngSeed::<Rng>::default, RngSeed::<Rng>::from_seed),
78 GlobalRng,
79 ));
80
81 world.add_observer(crate::observers::seed_from_global::<Rng, Rng>);
82 world.add_observer(crate::observers::seed_from_parent::<Rng, Rng>);
83 world.add_observer(crate::observers::seed_linked::<Rng, Rng>);
84 world.add_observer(crate::observers::trigger_seed_linked::<Rng, Rng>);
85
86 world.flush();
87 }
88}
89
90/// [`Plugin`] for setting up relations/observers for handling related Rngs. It takes two generic parameters,
91/// the first is the `Source` Rng, which is the algorithm for the source Rng entity, and then the second
92/// is the `Target` Rng, which is the algorithm for the targets. It follows a One to One/Many relationship
93/// model, going from `Source` to `Target`, where `Source` can have one or many `Target`s.
94///
95/// Note: This is for RNG algorithms, not Components. For more information, please read the
96/// [tutorial](https://docs.rs/bevy_rand/latest/bevy_rand/tutorial/ch05_observer_driven_reseeding/index.html).
97///
98/// ```
99/// use bevy_app::prelude::*;
100/// use bevy_prng::{ChaCha8Rng, WyRand};
101/// use bevy_rand::prelude::{EntropyPlugin, EntropyRelationsPlugin};
102///
103/// App::new()
104/// .add_plugins((
105/// // First initialise the RNGs. This also initialises observers for WyRand -> WyRand
106/// // and ChaCha8Rng -> ChaCha8Rng seeding relations
107/// EntropyPlugin::<ChaCha8Rng>::default(),
108/// EntropyPlugin::<WyRand>::default(),
109/// // You only need to explicitly provide the relations plugin for cross PRNG relations.
110/// // For example: This initialises observers for ChaCha8Rng -> WyRand seeding relations
111/// EntropyRelationsPlugin::<ChaCha8Rng, WyRand>::default(),
112/// ))
113/// .run();
114/// ```
115pub struct EntropyRelationsPlugin<Source, Target> {
116 _source: PhantomData<Source>,
117 _target: PhantomData<Target>,
118}
119
120impl<Source: EntropySource, Target: EntropySource> Default
121 for EntropyRelationsPlugin<Source, Target>
122{
123 fn default() -> Self {
124 Self {
125 _source: PhantomData,
126 _target: PhantomData,
127 }
128 }
129}
130
131impl<Source: EntropySource, Target: EntropySource> Plugin
132 for EntropyRelationsPlugin<Source, Target>
133{
134 fn build(&self, app: &mut App) {
135 let world = app.world_mut();
136
137 world.add_observer(crate::observers::seed_from_global::<Source, Target>);
138 world.add_observer(crate::observers::seed_from_parent::<Source, Target>);
139 world.add_observer(crate::observers::seed_linked::<Source, Target>);
140 world.add_observer(crate::observers::trigger_seed_linked::<Source, Target>);
141
142 world.flush();
143 }
144}