Expand wire protocol with version field, GameTime (day/phase/paused), FacingDirection (8-directional), VisibleTile, VisibilitySector (Forward/Peripheral), and visibility tag on VisibleEntity. Regenerate all msgpack fixtures for client compatibility. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
//! Run with: cargo test --test gen_fixtures -- --ignored
|
||||
|
||||
use settled_reach_server::bridge::types::*;
|
||||
use settled_reach_server::simulation::time::DayPhase;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
@@ -14,30 +15,45 @@ fn write_fixture(name: &str, bytes: &[u8]) {
|
||||
eprintln!("Wrote {} ({} bytes)", path.display(), bytes.len());
|
||||
}
|
||||
|
||||
/// Helper to create a minimal v2 snapshot for fixtures
|
||||
fn fixture_snapshot(tick: u64, entities: Vec<VisibleEntity>) -> ObserverSnapshot {
|
||||
ObserverSnapshot {
|
||||
version: 2,
|
||||
tick,
|
||||
game_time: GameTime {
|
||||
day: 0,
|
||||
time_of_day: 0,
|
||||
day_phase: DayPhase::Morning,
|
||||
paused: false,
|
||||
},
|
||||
player_facing: FacingDirection::North,
|
||||
entities,
|
||||
visible_tiles: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // Run manually: cargo test --test gen_fixtures -- --ignored
|
||||
fn generate_msgpack_fixtures() {
|
||||
// Snapshot with one NPC entity
|
||||
let snapshot = ObserverSnapshot {
|
||||
tick: 42,
|
||||
entities: vec![VisibleEntity {
|
||||
let snapshot = fixture_snapshot(
|
||||
42,
|
||||
vec![VisibleEntity {
|
||||
entity_id: 1,
|
||||
x: 10.0,
|
||||
y: 20.0,
|
||||
z: 0,
|
||||
kind: EntityKind::Npc,
|
||||
visibility: VisibilitySector::Forward,
|
||||
}],
|
||||
};
|
||||
);
|
||||
write_fixture(
|
||||
"snapshot_one_npc",
|
||||
&rmp_serde::to_vec_named(&snapshot).unwrap(),
|
||||
);
|
||||
|
||||
// Empty snapshot
|
||||
let empty = ObserverSnapshot {
|
||||
tick: 0,
|
||||
entities: vec![],
|
||||
};
|
||||
let empty = fixture_snapshot(0, vec![]);
|
||||
write_fixture("snapshot_empty", &rmp_serde::to_vec_named(&empty).unwrap());
|
||||
|
||||
// PlayerInput: MoveNorth
|
||||
@@ -60,32 +76,34 @@ fn generate_msgpack_fixtures() {
|
||||
&rmp_serde::to_vec_named(&input_perception).unwrap(),
|
||||
);
|
||||
|
||||
// Snapshot with Player entity (EntityKind::Player added by server team)
|
||||
let snapshot_player = ObserverSnapshot {
|
||||
tick: 1,
|
||||
entities: vec![VisibleEntity {
|
||||
// Snapshot with Player entity
|
||||
let snapshot_player = fixture_snapshot(
|
||||
1,
|
||||
vec![VisibleEntity {
|
||||
entity_id: 100,
|
||||
x: 16.5,
|
||||
y: 16.5,
|
||||
z: 0,
|
||||
kind: EntityKind::Player,
|
||||
visibility: VisibilitySector::Forward,
|
||||
}],
|
||||
};
|
||||
);
|
||||
write_fixture(
|
||||
"snapshot_player",
|
||||
&rmp_serde::to_vec_named(&snapshot_player).unwrap(),
|
||||
);
|
||||
|
||||
// Snapshot with multiple entities and all EntityKind variants
|
||||
let snapshot_multi = ObserverSnapshot {
|
||||
tick: 999,
|
||||
entities: vec![
|
||||
let snapshot_multi = fixture_snapshot(
|
||||
999,
|
||||
vec![
|
||||
VisibleEntity {
|
||||
entity_id: 1,
|
||||
x: 16.5,
|
||||
y: 16.5,
|
||||
z: 0,
|
||||
kind: EntityKind::Player,
|
||||
visibility: VisibilitySector::Forward,
|
||||
},
|
||||
VisibleEntity {
|
||||
entity_id: 2,
|
||||
@@ -93,6 +111,7 @@ fn generate_msgpack_fixtures() {
|
||||
y: 10.0,
|
||||
z: 0,
|
||||
kind: EntityKind::Npc,
|
||||
visibility: VisibilitySector::Peripheral,
|
||||
},
|
||||
VisibleEntity {
|
||||
entity_id: 3,
|
||||
@@ -100,6 +119,7 @@ fn generate_msgpack_fixtures() {
|
||||
y: 3.0,
|
||||
z: 1,
|
||||
kind: EntityKind::Object,
|
||||
visibility: VisibilitySector::Forward,
|
||||
},
|
||||
VisibleEntity {
|
||||
entity_id: 4,
|
||||
@@ -107,12 +127,58 @@ fn generate_msgpack_fixtures() {
|
||||
y: 0.0,
|
||||
z: -1,
|
||||
kind: EntityKind::Terrain,
|
||||
visibility: VisibilitySector::Forward,
|
||||
},
|
||||
],
|
||||
);
|
||||
write_fixture(
|
||||
"snapshot_multi_entity",
|
||||
&rmp_serde::to_vec_named(&snapshot_multi).unwrap(),
|
||||
);
|
||||
|
||||
// v2 snapshot with visible_tiles and game_time populated
|
||||
let snapshot_v2_full = ObserverSnapshot {
|
||||
version: 2,
|
||||
tick: 500,
|
||||
game_time: GameTime {
|
||||
day: 1,
|
||||
time_of_day: 720,
|
||||
day_phase: DayPhase::Evening,
|
||||
paused: false,
|
||||
},
|
||||
player_facing: FacingDirection::Southeast,
|
||||
entities: vec![VisibleEntity {
|
||||
entity_id: 1,
|
||||
x: 10.5,
|
||||
y: 10.5,
|
||||
z: 0,
|
||||
kind: EntityKind::Player,
|
||||
visibility: VisibilitySector::Forward,
|
||||
}],
|
||||
visible_tiles: vec![
|
||||
VisibleTile {
|
||||
x: 10,
|
||||
y: 10,
|
||||
z: 0,
|
||||
visibility: VisibilitySector::Forward,
|
||||
},
|
||||
VisibleTile {
|
||||
x: 11,
|
||||
y: 10,
|
||||
z: 0,
|
||||
visibility: VisibilitySector::Peripheral,
|
||||
},
|
||||
VisibleTile {
|
||||
x: 10,
|
||||
y: 9,
|
||||
z: 0,
|
||||
visibility: VisibilitySector::Forward,
|
||||
},
|
||||
],
|
||||
};
|
||||
write_fixture(
|
||||
"snapshot_multi_entity",
|
||||
&rmp_serde::to_vec_named(&snapshot_multi).unwrap(),
|
||||
"snapshot_v2_full",
|
||||
&rmp_serde::to_vec_named(&snapshot_v2_full).unwrap(),
|
||||
);
|
||||
|
||||
// Batch input: Vec<PlayerInput> with two actions (D-030 Layer 1 bidirectional symmetry)
|
||||
|
||||
+113
-12
@@ -1,24 +1,44 @@
|
||||
//! IPC serialization round-trip tests (D-030 Layer 1: fixture-based).
|
||||
|
||||
use settled_reach_server::bridge::types::*;
|
||||
use settled_reach_server::simulation::time::DayPhase;
|
||||
use std::fs;
|
||||
|
||||
/// Helper to create a minimal v2 snapshot for tests
|
||||
fn test_snapshot(tick: u64, entities: Vec<VisibleEntity>) -> ObserverSnapshot {
|
||||
ObserverSnapshot {
|
||||
version: 2,
|
||||
tick,
|
||||
game_time: GameTime {
|
||||
day: 0,
|
||||
time_of_day: 0,
|
||||
day_phase: DayPhase::Morning,
|
||||
paused: false,
|
||||
},
|
||||
player_facing: FacingDirection::North,
|
||||
entities,
|
||||
visible_tiles: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn observer_snapshot_roundtrip() {
|
||||
let snapshot = ObserverSnapshot {
|
||||
tick: 42,
|
||||
entities: vec![VisibleEntity {
|
||||
let snapshot = test_snapshot(
|
||||
42,
|
||||
vec![VisibleEntity {
|
||||
entity_id: 1,
|
||||
x: 10.0,
|
||||
y: 20.0,
|
||||
z: 0,
|
||||
kind: EntityKind::Npc,
|
||||
visibility: VisibilitySector::Forward,
|
||||
}],
|
||||
};
|
||||
);
|
||||
|
||||
let bytes = rmp_serde::to_vec_named(&snapshot).expect("serialize");
|
||||
let decoded: ObserverSnapshot = rmp_serde::from_slice(&bytes).expect("deserialize");
|
||||
|
||||
assert_eq!(decoded.version, 2);
|
||||
assert_eq!(decoded.tick, 42);
|
||||
assert_eq!(decoded.entities.len(), 1);
|
||||
assert_eq!(decoded.entities[0].entity_id, 1);
|
||||
@@ -39,10 +59,7 @@ fn player_input_roundtrip() {
|
||||
|
||||
#[test]
|
||||
fn empty_snapshot_roundtrip() {
|
||||
let snapshot = ObserverSnapshot {
|
||||
tick: 0,
|
||||
entities: vec![],
|
||||
};
|
||||
let snapshot = test_snapshot(0, vec![]);
|
||||
|
||||
let bytes = rmp_serde::to_vec_named(&snapshot).expect("serialize");
|
||||
let decoded: ObserverSnapshot = rmp_serde::from_slice(&bytes).expect("deserialize");
|
||||
@@ -140,11 +157,9 @@ fn all_entity_kind_variants_roundtrip() {
|
||||
y: 0.0,
|
||||
z: 0,
|
||||
kind,
|
||||
visibility: VisibilitySector::Forward,
|
||||
};
|
||||
let snapshot = ObserverSnapshot {
|
||||
tick: 0,
|
||||
entities: vec![entity],
|
||||
};
|
||||
let snapshot = test_snapshot(0, vec![entity]);
|
||||
let bytes = rmp_serde::to_vec_named(&snapshot).expect("serialize");
|
||||
let decoded: ObserverSnapshot = rmp_serde::from_slice(&bytes).expect("deserialize");
|
||||
let re_bytes = rmp_serde::to_vec_named(&decoded).expect("re-serialize");
|
||||
@@ -154,3 +169,89 @@ fn all_entity_kind_variants_roundtrip() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// v2 snapshot fields round-trip correctly
|
||||
#[test]
|
||||
fn snapshot_v2_fields_roundtrip() {
|
||||
let snapshot = ObserverSnapshot {
|
||||
version: 2,
|
||||
tick: 100,
|
||||
game_time: GameTime {
|
||||
day: 3,
|
||||
time_of_day: 720,
|
||||
day_phase: DayPhase::Evening,
|
||||
paused: true,
|
||||
},
|
||||
player_facing: FacingDirection::Southeast,
|
||||
entities: vec![VisibleEntity {
|
||||
entity_id: 1,
|
||||
x: 5.5,
|
||||
y: 10.5,
|
||||
z: 0,
|
||||
kind: EntityKind::Player,
|
||||
visibility: VisibilitySector::Forward,
|
||||
}],
|
||||
visible_tiles: vec![
|
||||
VisibleTile {
|
||||
x: 5,
|
||||
y: 10,
|
||||
z: 0,
|
||||
visibility: VisibilitySector::Forward,
|
||||
},
|
||||
VisibleTile {
|
||||
x: 6,
|
||||
y: 10,
|
||||
z: 0,
|
||||
visibility: VisibilitySector::Peripheral,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
let bytes = rmp_serde::to_vec_named(&snapshot).expect("serialize");
|
||||
let decoded: ObserverSnapshot = rmp_serde::from_slice(&bytes).expect("deserialize");
|
||||
|
||||
assert_eq!(decoded.version, 2);
|
||||
assert_eq!(decoded.game_time.day, 3);
|
||||
assert_eq!(decoded.game_time.time_of_day, 720);
|
||||
assert_eq!(decoded.game_time.day_phase, DayPhase::Evening);
|
||||
assert!(decoded.game_time.paused);
|
||||
assert_eq!(decoded.player_facing, FacingDirection::Southeast);
|
||||
assert_eq!(decoded.visible_tiles.len(), 2);
|
||||
assert_eq!(decoded.visible_tiles[0].visibility, VisibilitySector::Forward);
|
||||
assert_eq!(decoded.visible_tiles[1].visibility, VisibilitySector::Peripheral);
|
||||
assert_eq!(decoded.entities[0].visibility, VisibilitySector::Forward);
|
||||
}
|
||||
|
||||
/// All FacingDirection variants round-trip
|
||||
#[test]
|
||||
fn all_facing_direction_variants_roundtrip() {
|
||||
let directions = [
|
||||
FacingDirection::North,
|
||||
FacingDirection::Northeast,
|
||||
FacingDirection::East,
|
||||
FacingDirection::Southeast,
|
||||
FacingDirection::South,
|
||||
FacingDirection::Southwest,
|
||||
FacingDirection::West,
|
||||
FacingDirection::Northwest,
|
||||
];
|
||||
|
||||
for dir in directions {
|
||||
let snapshot = ObserverSnapshot {
|
||||
version: 2,
|
||||
tick: 0,
|
||||
game_time: GameTime {
|
||||
day: 0,
|
||||
time_of_day: 0,
|
||||
day_phase: DayPhase::Morning,
|
||||
paused: false,
|
||||
},
|
||||
player_facing: dir,
|
||||
entities: vec![],
|
||||
visible_tiles: vec![],
|
||||
};
|
||||
let bytes = rmp_serde::to_vec_named(&snapshot).expect("serialize");
|
||||
let decoded: ObserverSnapshot = rmp_serde::from_slice(&bytes).expect("deserialize");
|
||||
assert_eq!(decoded.player_facing, dir);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user