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:
2026-02-11 16:54:40 +01:00
co-authored by Claude Opus 4.6
parent 84925b334a
commit f67caf1986
18 changed files with 2036 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
// Bridge module - Client-server communication
// Implements D-020 subprocess/IPC architecture
// MessagePack serialization for Rust<->Godot communication
use bevy_app::prelude::*;
pub mod types;
pub use types::*;
/// Error type for bridge operations
#[derive(Debug, thiserror::Error)]
pub enum BridgeError {
#[error("serialization error: {0}")]
Serialization(#[from] rmp_serde::encode::Error),
#[error("deserialization error: {0}")]
Deserialization(#[from] rmp_serde::decode::Error),
#[error("transport error: {0}")]
Transport(String),
}
/// Abstracts transport layer (D-020)
/// Implemented by LocalBridge (stdio) and future NetworkBridge
pub trait SimBridge: Send + Sync {
/// Send an observer snapshot to the client
fn send_snapshot(&self, snapshot: &ObserverSnapshot) -> Result<(), BridgeError>;
/// Receive player inputs from the client
fn receive_inputs(&self) -> Result<Vec<PlayerInput>, BridgeError>;
}
/// Bridge plugin for client-server communication
/// Abstracts transport layer (LocalBridge/NetworkBridge)
pub struct BridgePlugin;
impl Plugin for BridgePlugin {
fn build(&self, _app: &mut App) {
// Stub implementation - will be populated in phase 2
tracing::debug!("BridgePlugin initialized");
}
}
+56
View File
@@ -0,0 +1,56 @@
// Bridge type definitions
// ObserverSnapshot: data crossing the client-server boundary
// PlayerInput: semantic actions from client
use serde::{Deserialize, Serialize};
/// The ONLY data structure crossing the client-server boundary (D-020)
/// Contains all information visible to the observer at a given tick
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ObserverSnapshot {
/// Simulation tick when this snapshot was produced
pub tick: u64,
/// All entities visible to the observer
pub entities: Vec<VisibleEntity>,
}
/// A visible entity in the simulation
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VisibleEntity {
pub entity_id: u64,
pub x: f32,
pub y: f32,
pub z: i32,
pub kind: EntityKind,
}
/// Category of visible entity
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EntityKind {
Npc,
Object,
Terrain,
}
/// Semantic player actions, not raw key events (D-020)
/// Timestamped for deterministic processing
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlayerInput {
/// Tick when this input was issued
pub tick: u64,
/// The action to perform
pub action: PlayerAction,
}
/// Player action variants
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PlayerAction {
MoveNorth,
MoveSouth,
MoveEast,
MoveWest,
Interact,
UsePerceptionMode(String),
Pause,
Unpause,
}