feat(simulation): add world_seed IPC and EntanglementConfig (#175, #178)

Implements the StartupMessage protocol: client generates world_seed in
SessionManager.new_game(), sends it after handshake, server uses it to
seed SimRng and sample EntanglementConfig.

EntanglementConfig samples flat ∈ [25,35]%, intrigue ∈ [15,25]%, mundane
as remainder (D-029). Same seed produces identical config (D-010
determinism). Different seeds produce distinct configs in ≥90% of pairs.

Protocol flow: HandshakeMessage (server→client) → StartupMessage with
world_seed (client→server) → SimRng initialization → tick loop.

10 Rust tests (determinism, variation, bounds, sum invariant).
9 GDScript test stubs + 2 encode tests for client-side pipeline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 14:26:31 +01:00
co-authored by Claude Opus 4.6
parent ebc87d8e74
commit d591f44b35
13 changed files with 640 additions and 7 deletions
+9 -4
View File
@@ -84,7 +84,12 @@ fn server_subprocess_sends_snapshot_on_connect() {
handshake.protocol_version, PROTOCOL_VERSION
);
// 5. Send one PlayerInput (idle tick 0)
// 5. Send StartupMessage with world_seed (#175)
let startup = StartupMessage { world_seed: 42 };
let startup_payload = rmp_serde::to_vec_named(&startup).expect("serialize StartupMessage");
write_framed(&mut writer, &startup_payload).expect("send StartupMessage to server");
// 6. Send one PlayerInput (idle tick 0)
let inputs = vec![PlayerInput {
tick: 0,
action: PlayerAction::MoveNorth,
@@ -92,14 +97,14 @@ fn server_subprocess_sends_snapshot_on_connect() {
let payload = rmp_serde::to_vec_named(&inputs).expect("serialize PlayerInput");
write_framed(&mut writer, &payload).expect("send PlayerInput to server");
// 6. Read one ObserverSnapshot
// 7. Read one ObserverSnapshot
let response = read_framed(&mut reader)
.expect("read snapshot frame")
.expect("server closed connection before sending snapshot");
let snapshot: ObserverSnapshot =
rmp_serde::from_slice(&response).expect("deserialize ObserverSnapshot");
// 7. Assert protocol correctness (D-020)
// 8. Assert protocol correctness (D-020)
assert_eq!(
snapshot.version, PROTOCOL_VERSION,
"protocol version mismatch: got {}, expected {}",
@@ -117,7 +122,7 @@ fn server_subprocess_sends_snapshot_on_connect() {
.any(|e| matches!(e.kind, EntityKind::Player));
assert!(has_player, "snapshot must contain a Player entity");
// 8. Clean up: drop connection so the server exits its game loop
// 9. Clean up: drop connection so the server exits its game loop
drop(reader);
drop(writer);