feat(server): initialize Rust/bevy_ecs simulation server
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>
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
//! IPC serialization round-trip tests (D-030 Layer 1: fixture-based).
|
||||
|
||||
use settled_reach_server::bridge::types::*;
|
||||
|
||||
#[test]
|
||||
fn observer_snapshot_roundtrip() {
|
||||
let snapshot = ObserverSnapshot {
|
||||
tick: 42,
|
||||
entities: vec![VisibleEntity {
|
||||
entity_id: 1,
|
||||
x: 10.0,
|
||||
y: 20.0,
|
||||
z: 0,
|
||||
kind: EntityKind::Npc,
|
||||
}],
|
||||
};
|
||||
|
||||
let bytes = rmp_serde::to_vec(&snapshot).expect("serialize");
|
||||
let decoded: ObserverSnapshot = rmp_serde::from_slice(&bytes).expect("deserialize");
|
||||
|
||||
assert_eq!(decoded.tick, 42);
|
||||
assert_eq!(decoded.entities.len(), 1);
|
||||
assert_eq!(decoded.entities[0].entity_id, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn player_input_roundtrip() {
|
||||
let input = PlayerInput {
|
||||
tick: 100,
|
||||
action: PlayerAction::MoveNorth,
|
||||
};
|
||||
|
||||
let bytes = rmp_serde::to_vec(&input).expect("serialize");
|
||||
let decoded: PlayerInput = rmp_serde::from_slice(&bytes).expect("deserialize");
|
||||
|
||||
assert_eq!(decoded.tick, 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_snapshot_roundtrip() {
|
||||
let snapshot = ObserverSnapshot {
|
||||
tick: 0,
|
||||
entities: vec![],
|
||||
};
|
||||
|
||||
let bytes = rmp_serde::to_vec(&snapshot).expect("serialize");
|
||||
let decoded: ObserverSnapshot = rmp_serde::from_slice(&bytes).expect("deserialize");
|
||||
|
||||
assert_eq!(decoded.tick, 0);
|
||||
assert!(decoded.entities.is_empty());
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
//! Smoke test: the simulation world boots and can run a single tick.
|
||||
|
||||
use bevy_app::prelude::*;
|
||||
use settled_reach_server::simulation::SimulationPlugin;
|
||||
use settled_reach_server::simulation::time::SimulationTime;
|
||||
|
||||
#[test]
|
||||
fn world_boots_and_ticks() {
|
||||
let mut app = App::new();
|
||||
app.add_plugins(SimulationPlugin);
|
||||
|
||||
// Verify initial state
|
||||
let time = app.world().resource::<SimulationTime>();
|
||||
assert_eq!(time.tick, 0);
|
||||
|
||||
// Run one update cycle
|
||||
app.update();
|
||||
|
||||
// Verify tick advanced
|
||||
let time = app.world().resource::<SimulationTime>();
|
||||
assert_eq!(time.tick, 1);
|
||||
}
|
||||
Reference in New Issue
Block a user