feat(simulation): #523 add zone_id to ObserverSnapshot (D-077, protocol v11)
Server-tracked zone_id on VisibleTile for D-073 zone crossfade and D-059 deep fog temperature tint. ZoneMap resource backed by BTreeMap, observer enrichment in snapshot assembly. Backwards-compatible: v10 payloads deserialize with zone_id: None. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -188,6 +188,7 @@ fn generate_msgpack_fixtures() {
|
||||
z: 0,
|
||||
visibility: VisibilitySector::Forward,
|
||||
tile_kind: TileKind::Floor,
|
||||
zone_id: Some(1),
|
||||
},
|
||||
VisibleTile {
|
||||
x: 11,
|
||||
@@ -195,6 +196,7 @@ fn generate_msgpack_fixtures() {
|
||||
z: 0,
|
||||
visibility: VisibilitySector::Peripheral,
|
||||
tile_kind: TileKind::Floor,
|
||||
zone_id: Some(1),
|
||||
},
|
||||
VisibleTile {
|
||||
x: 10,
|
||||
@@ -202,6 +204,7 @@ fn generate_msgpack_fixtures() {
|
||||
z: 0,
|
||||
visibility: VisibilitySector::Forward,
|
||||
tile_kind: TileKind::Floor,
|
||||
zone_id: None,
|
||||
},
|
||||
],
|
||||
nearby_interactions: vec![],
|
||||
|
||||
@@ -241,6 +241,7 @@ fn snapshot_v2_fields_roundtrip() {
|
||||
z: 0,
|
||||
visibility: VisibilitySector::Forward,
|
||||
tile_kind: TileKind::Floor,
|
||||
zone_id: None,
|
||||
},
|
||||
VisibleTile {
|
||||
x: 6,
|
||||
@@ -248,6 +249,7 @@ fn snapshot_v2_fields_roundtrip() {
|
||||
z: 0,
|
||||
visibility: VisibilitySector::Peripheral,
|
||||
tile_kind: TileKind::Wall,
|
||||
zone_id: None,
|
||||
},
|
||||
],
|
||||
nearby_interactions: vec![],
|
||||
@@ -312,7 +314,7 @@ fn protocol_version_constant_matches_snapshot() {
|
||||
let snapshot = test_snapshot(0, vec![]);
|
||||
assert_eq!(snapshot.version, PROTOCOL_VERSION);
|
||||
assert_eq!(
|
||||
PROTOCOL_VERSION, 10,
|
||||
PROTOCOL_VERSION, 11,
|
||||
"bump this assertion when protocol version changes"
|
||||
);
|
||||
}
|
||||
@@ -862,6 +864,7 @@ fn boundary_value_in_tile_position() {
|
||||
z: 0,
|
||||
visibility: VisibilitySector::Forward,
|
||||
tile_kind: TileKind::Floor,
|
||||
zone_id: None,
|
||||
}];
|
||||
let bytes = rmp_serde::to_vec_named(&snapshot)
|
||||
.unwrap_or_else(|e| panic!("encode tile x/y={} failed: {}", tile_val, e));
|
||||
@@ -1264,6 +1267,83 @@ fn v9_payload_deserializes_into_v10_struct() {
|
||||
);
|
||||
}
|
||||
|
||||
/// v10 payload (without zone_id on VisibleTile) deserializes into the v11 struct
|
||||
/// via #[serde(default)]. Guards backwards compat during migration (#523, D-077).
|
||||
#[test]
|
||||
fn v10_payload_deserializes_into_v11_struct() {
|
||||
// V10 VisibleTile: no zone_id field
|
||||
#[derive(serde::Serialize)]
|
||||
struct VisibleTileV10 {
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
visibility: VisibilitySector,
|
||||
tile_kind: TileKind,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
struct ObserverSnapshotV10 {
|
||||
version: u8,
|
||||
tick: u64,
|
||||
game_time: GameTime,
|
||||
player_facing: FacingDirection,
|
||||
player_stance: MovementStance,
|
||||
player_inventory: Vec<InventoryItem>,
|
||||
entities: Vec<VisibleEntity>,
|
||||
visible_tiles: Vec<VisibleTileV10>,
|
||||
nearby_interactions: Vec<NearbyInteraction>,
|
||||
current_monologue: Option<MonologueEvent>,
|
||||
pending_recognitions: Vec<PendingRecognitionWire>,
|
||||
dialogue_response: Option<DialogueResponseEvent>,
|
||||
blocked_entities: Vec<u64>,
|
||||
scan_events: Vec<settled_reach_server::simulation::contraband::ScanEvent>,
|
||||
sound_events: Vec<settled_reach_server::simulation::sound::SoundEvent>,
|
||||
rng_seed: Option<u64>,
|
||||
}
|
||||
|
||||
let v10 = ObserverSnapshotV10 {
|
||||
version: 10,
|
||||
tick: 300,
|
||||
game_time: GameTime {
|
||||
day: 0,
|
||||
time_of_day: 0,
|
||||
day_phase: DayPhase::Morning,
|
||||
tick_rate: TickRate::Full,
|
||||
},
|
||||
player_facing: FacingDirection::North,
|
||||
player_stance: MovementStance::Walk,
|
||||
player_inventory: vec![],
|
||||
entities: vec![],
|
||||
visible_tiles: vec![VisibleTileV10 {
|
||||
x: 5,
|
||||
y: 10,
|
||||
z: 0,
|
||||
visibility: VisibilitySector::Forward,
|
||||
tile_kind: TileKind::Floor,
|
||||
}],
|
||||
nearby_interactions: vec![],
|
||||
current_monologue: None,
|
||||
pending_recognitions: vec![],
|
||||
dialogue_response: None,
|
||||
blocked_entities: vec![],
|
||||
scan_events: vec![],
|
||||
sound_events: vec![],
|
||||
rng_seed: Some(42),
|
||||
};
|
||||
|
||||
let bytes = rmp_serde::to_vec_named(&v10).expect("serialize v10");
|
||||
let decoded: ObserverSnapshot = rmp_serde::from_slice(&bytes)
|
||||
.expect("v10 payload should deserialize into v11 struct via serde(default)");
|
||||
|
||||
assert_eq!(decoded.version, 10, "version field preserved from v10");
|
||||
assert_eq!(decoded.tick, 300);
|
||||
assert_eq!(decoded.visible_tiles.len(), 1);
|
||||
assert_eq!(
|
||||
decoded.visible_tiles[0].zone_id, None,
|
||||
"missing zone_id should default to None"
|
||||
);
|
||||
}
|
||||
|
||||
/// NearbyInteraction.object_type round-trips through MessagePack (#422).
|
||||
/// Verifies object_type=Some(Container) survives the wire.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user