15 releases (8 breaking)
0.9.0 | Jul 4, 2024 |
---|---|
0.8.2 | Feb 24, 2024 |
0.7.0 | Nov 4, 2023 |
0.6.0 | Jul 10, 2023 |
0.2.0 | Jul 30, 2022 |
#239 in Game dev
401 downloads per month
Used in 3 crates
47KB
591 lines
bevy_turborand
A plugin to enable random number generation for the Bevy game engine, built upon turborand
. Implements ideas from Bevy's Deterministic RNG RFC.
turborand
's internal implementation uses Wyrand, a simple and fast generator but not cryptographically secure, as well as ChaCha8, a cryptographically secure generator tuned to 8 rounds of the ChaCha algorithm for increased throughput without sacrificing too much security, as per the recommendations in the Too Much Crypto paper.
Example
use bevy::prelude::*;
use bevy_turborand::prelude::*;
#[derive(Debug, Component)]
struct Player;
fn setup_player(mut commands: Commands, mut global_rng: ResMut<GlobalRng>) {
commands.spawn((
Player,
RngComponent::from(&mut global_rng)
));
}
fn do_damage(mut q_player: Query<&mut RngComponent, With<Player>>) {
let mut rng = q_player.single_mut();
println!("Player attacked for {} damage!", rng.u32(10..=20));
}
fn main() {
App::new()
.add_plugins(RngPlugin::default())
.add_systems(Startup, setup_player)
.add_systems(Update, do_damage)
.run();
}
Deterministic RNG
In order to obtain determinism for your game/app, the Rng
's must be seeded. GlobalRng
and RngPlugin
can be given a seed which then sets the internal PRNG to behave deterministically. Instead of having to seed every RngComponent
manually, as long as the GlobalRng
is seeded, then RngComponent
can be created directly from the global instance, cloning the internal Rng to itself, which gives it a random but deterministic seed. This allows for better randomised states among RngComponent
s while still having a deterministic app.
Systems also must be ordered correctly for determinism to occur. Systems however do not need to be strictly ordered against every one as if some linear path. Only related systems that access a given set of RngComponent
s need to be ordered. Ones that are unrelated can run in parallel and still yield a deterministic result. So systems selecting a Player
entity with a RngComponent
should all be ordered against each other, but systems selecting an Item
entity with an RngComponent
that never interacts with Player
don't need to be ordered with Player
systems, only between themselves.
To see an example of this, view the project's tests to see how to make use of determinism for testing random systems.
Supported Versions
bevy_turborand |
bevy |
---|---|
v0.9.0-rc.1 | v0.14.0-rc.4 |
v0.8 | v0.13 |
v0.7 | v0.12 |
v0.6 | v0.11 |
v0.5 | v0.10 |
v0.4 | v0.9 |
v0.2, v0.3 | v0.8 |
v0.1 | v0.7 |
MSRV for bevy_turborand
is the same as in bevy
, so always the latest Rust compiler version.
Migration Guide from 0.2 to 0.3
With turborand
0.6, there are a lot of breaking changes due to a rework of the API. For the most part, this is mostly internal to turborand
and bevy_turborand
exposes the new traits by default, so any existing code should more or less work fine, except for the following:
from_global
onRngComponent
no longer exists. Instead, there areFrom
implementations onRngComponent
andChaChaRngComponent
that cover more use-cases where a reference or resource or even another component could be used for initialising a newRngComponent
and so forth. This makes it more flexible with regards to what the source is. Just go to town withRngComponent::from
.new
functions no longer accept an Option parameter for the seed. The methods are split betweennew
for initialising without a seed (so obtaining a random seed), andwith_seed
for initialising with a seed value (which applies to components and resources).RngPlugin
now uses a builder pattern to initialise.new
creates a default state with no seeds applied, and thenwith_rng_seed
andwith_chacha_seed
applies seed values to the plugin to then initialise the global RNG resources with. See the docs for an example of how that might look now.bevy_turborand
now has a number of feature flags, and apart from the new traits (which are always provided when no flags are enabled), everything else is behind a feature flag. For example,wyrand
based structs (RngComponent
et al) are behind thewyrand
flag, which is enabled by default. For a higher quality entropy source (though it will be slower),chacha
flag provides RNG provided by the ChaCha8 algorithm, such asChaChaRngComponent
.RngPlugin
is available when eitherwyrand
orchacha
is enabled. Otherwise, existing flags likerand
enable the rand crate compatibility layer, andserialize
for serde derives.
Migration Guide from 0.3 to 0.4
bevy_turborand
moves to turborand
0.8, which rolls with a couple of major API breaking changes. Certain traits are no longer exposed as they are internal implementation details. The main changes are that ChaChaRng
is no longer backed by a Vec
for buffering entropy, switching to an aligned array for improving generation throughput at the slight cost of initialisation performance and struct size. It does mean no need for the single heap allocation however when the RNG generates a number for the first time. This refactor also changes how ChaChaRng
is serialised, so bevy_turborand
0.4 is not compatible with previously serialised data.
Also, the old Clone
behaviour for TurboCore
RNGs has been changed, so .clone()
now maintains the state between original and cloned instances. The old behaviour now exists as the ForkableCore
trait with the .fork()
method, which has the original instance's state be mutated in order to derive a new random state for the forked instance. As such, RngComponent
and ChaChaRngComponent
can now implement Clone
.
Migration Guide from 0.4 to 0.5
bevy_turborand
moves to turborand
0.10, which introduces a few more sample/sample_multiple methods for supporting iterators, partial_shuffle
and the major change regarding stable indexing, with sample/shuffle methods using the new index
method. index
allows for sampling to be stable across platforms, though it is currently optimised for 64-bit systems. All sampling/shuffling methods now make use of index
, so this means bevy_turborand
will be deterministic across different platforms, such as having the same output for wasm32
and x86-64
. The only method that doesn't benefit from this is usize
.
ChaChaRngComponent
also now has a different output due to a change of the internal ChaChaRng
source, which also changes how it gets serialised.
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Dependencies
~24MB
~458K SLoC