Server boilerplate epic (276) complete. Establishes the Rust simulation server foundation per D-020 (subprocess/IPC architecture). Structure: - bevy_ecs 0.18 + bevy_app 0.18, MessagePack serialization (rmp-serde) - SimulationPlugin with deterministic resources: SimulationTime (D-031), SimRng (D-030), InputQueue (D-010) - Core IPC types: ObserverSnapshot, PlayerInput, SimBridge trait (D-020) - CauseChain production component for provenance tracking (D-030) - SimulationTier types with LRU eviction support (D-026) - NPC 10-axis model components (D-024) - 15 tests: inline unit tests + integration smoke/serialization tests - make ci-server passes (clippy, fmt, build, test) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
55 lines
1.3 KiB
Rust
55 lines
1.3 KiB
Rust
// Simulation RNG system
|
|
// Injectable ChaCha RNG resource for deterministic replay (D-030)
|
|
// Ensures same seed produces same outcomes
|
|
|
|
use bevy_ecs::prelude::*;
|
|
use rand::SeedableRng;
|
|
use rand_chacha::ChaCha20Rng;
|
|
|
|
/// Simulation RNG resource
|
|
/// ChaCha20 RNG with stored seed for deterministic replay
|
|
#[derive(Resource)]
|
|
pub struct SimRng {
|
|
pub rng: ChaCha20Rng,
|
|
seed: u64,
|
|
}
|
|
|
|
impl SimRng {
|
|
/// Create a new SimRng with the given seed
|
|
pub fn new(seed: u64) -> Self {
|
|
Self {
|
|
rng: ChaCha20Rng::seed_from_u64(seed),
|
|
seed,
|
|
}
|
|
}
|
|
|
|
/// Get the seed used to initialize this RNG
|
|
pub fn seed(&self) -> u64 {
|
|
self.seed
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use rand::Rng;
|
|
|
|
#[test]
|
|
fn same_seed_same_sequence() {
|
|
let mut rng1 = SimRng::new(42);
|
|
let mut rng2 = SimRng::new(42);
|
|
let vals1: Vec<u32> = (0..100).map(|_| rng1.rng.random()).collect();
|
|
let vals2: Vec<u32> = (0..100).map(|_| rng2.rng.random()).collect();
|
|
assert_eq!(vals1, vals2);
|
|
}
|
|
|
|
#[test]
|
|
fn different_seed_different_sequence() {
|
|
let mut rng1 = SimRng::new(42);
|
|
let mut rng2 = SimRng::new(43);
|
|
let val1: u32 = rng1.rng.random();
|
|
let val2: u32 = rng2.rng.random();
|
|
assert_ne!(val1, val2);
|
|
}
|
|
}
|