feat(simulation): multi-threaded executor + EntityRng (#843 Part B)

Enable Bevy multi-threaded executor via bevy_tasks multi_threaded
feature. Systems within the same TickPhase that don't share mutable
resources now run in parallel automatically.

Add EntityRng component — per-entity ChaCha20Rng seeded from
world_seed + StableId via splitmix64 mixing. More deterministic than
shared SimRng (order-independent). Migrate all monologue systems
(4 of 13 SimRng consumers) to EntityRng, removing contention that
serialized them against conversation/dialogue systems.

Add rayon dependency (infrastructure only, no par_iter calls yet).

SimRng retained for world-level randomness: conversation pairing,
knowledge transfer, dialogue, ticker, storyteller.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-11 00:08:41 +02:00
co-authored by Claude Opus 4.6
parent 309c05d441
commit 2175e9b31c
5 changed files with 128 additions and 19 deletions
+16 -2
View File
@@ -199,7 +199,7 @@ fn main() {
std::process::exit(1);
}
} else {
setup_proof_room(&mut app, archetype);
setup_proof_room(&mut app, archetype, seed);
}
tracing::info!(
@@ -395,9 +395,11 @@ fn dump_schedule_graph() {
fn setup_proof_room(
app: &mut App,
archetype: settled_reach_server::bridge::types::CharacterArchetype,
world_seed: u64,
) {
use settled_reach_server::knowledge::registry::EntityRegistry;
use settled_reach_server::knowledge::KnowledgeGraph;
use settled_reach_server::simulation::rng::EntityRng;
use settled_reach_server::npc::relationships::{RelationshipEdge, RelationshipGraph};
use settled_reach_server::npc::{
Contentment, DailyRoutine, Npc, RelationshipKind, RoutineEntry, ToleranceThreshold, Want,
@@ -459,7 +461,10 @@ fn setup_proof_room(
PlayerMoveCooldown::default(),
))
.id();
registry.register(player);
let player_sid = registry.register(player);
app.world_mut()
.entity_mut(player)
.insert(EntityRng::from_seed_and_id(world_seed, player_sid.0));
// NPC 1: Dock worker at (16,13) — behind wall, full routine
let npc1 = app
@@ -507,6 +512,9 @@ fn setup_proof_room(
))
.id();
let npc1_sid = registry.register(npc1);
app.world_mut()
.entity_mut(npc1)
.insert(EntityRng::from_seed_and_id(world_seed, npc1_sid.0));
// NPC 2: Field tech at (14,18) — visible to player, has routine
let npc2 = app
@@ -544,6 +552,9 @@ fn setup_proof_room(
))
.id();
let npc2_sid = registry.register(npc2);
app.world_mut()
.entity_mut(npc2)
.insert(EntityRng::from_seed_and_id(world_seed, npc2_sid.0));
// NPC 3: Guard at (18,14) — stationary, no routine
let npc3 = app
@@ -565,6 +576,9 @@ fn setup_proof_room(
))
.id();
let npc3_sid = registry.register(npc3);
app.world_mut()
.entity_mut(npc3)
.insert(EntityRng::from_seed_and_id(world_seed, npc3_sid.0));
// Populate RelationshipGraph with a few edges
{