feat(client): enforce PROTOCOL_VERSION check in snapshot decode
Client now rejects snapshots where version != PROTOCOL_VERSION (4). Returns null with error log on mismatch. Test snapshot updated to use Protocol.PROTOCOL_VERSION and v4 game_time format (tick_rate replaces paused field). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -296,12 +296,12 @@ func _test_snapshot() -> Dictionary:
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
"tick": _test_tick,
|
"tick": _test_tick,
|
||||||
"version": 2,
|
"version": Protocol.PROTOCOL_VERSION,
|
||||||
"game_time": {
|
"game_time": {
|
||||||
"day": 0,
|
"day": 0,
|
||||||
"time_of_day": _test_tick * 10,
|
"time_of_day": _test_tick * 10,
|
||||||
"day_phase": "Morning",
|
"day_phase": "Morning",
|
||||||
"paused": false,
|
"tick_rate": "Full",
|
||||||
},
|
},
|
||||||
"player_facing": _test_facing,
|
"player_facing": _test_facing,
|
||||||
"entities": entities,
|
"entities": entities,
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ class_name Protocol
|
|||||||
## Unit enum variants (no data) → bare strings ("MoveNorth", "Npc")
|
## Unit enum variants (no data) → bare strings ("MoveNorth", "Npc")
|
||||||
## Data enum variants → single-element maps ({"UsePerceptionMode": "thermal"})
|
## Data enum variants → single-element maps ({"UsePerceptionMode": "thermal"})
|
||||||
|
|
||||||
|
## Protocol version — must match server PROTOCOL_VERSION in bridge/types.rs.
|
||||||
|
## Reject snapshots where version != this value.
|
||||||
|
const PROTOCOL_VERSION: int = 4
|
||||||
|
|
||||||
|
|
||||||
# -- Decode: bytes from server → GDScript types --------------------------------
|
# -- Decode: bytes from server → GDScript types --------------------------------
|
||||||
|
|
||||||
@@ -27,6 +31,12 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
|
|||||||
push_error("Protocol: snapshot missing required fields")
|
push_error("Protocol: snapshot missing required fields")
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
# Version check: reject snapshots from incompatible server
|
||||||
|
var version: Variant = raw.get("version")
|
||||||
|
if version != PROTOCOL_VERSION:
|
||||||
|
push_error("Protocol: version mismatch (got %s, expected %s). Server and client are out of sync." % [version, PROTOCOL_VERSION])
|
||||||
|
return null
|
||||||
|
|
||||||
var entities: Array[Dictionary] = []
|
var entities: Array[Dictionary] = []
|
||||||
var raw_entities: Array = raw["entities"]
|
var raw_entities: Array = raw["entities"]
|
||||||
var dropped := 0
|
var dropped := 0
|
||||||
@@ -44,8 +54,7 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
|
|||||||
# in any realistic scenario (would require ~29 billion years at 10 ticks/game-minute per D-031).
|
# in any realistic scenario (would require ~29 billion years at 10 ticks/game-minute per D-031).
|
||||||
var tick: int = raw["tick"]
|
var tick: int = raw["tick"]
|
||||||
|
|
||||||
# v2 fields — optional for backward compatibility
|
# version already checked above; game_time for HUD display
|
||||||
var version: Variant = raw.get("version")
|
|
||||||
var game_time: Variant = raw.get("game_time")
|
var game_time: Variant = raw.get("game_time")
|
||||||
|
|
||||||
# player_facing: FacingDirection is a unit enum → bare string in rmp_serde
|
# player_facing: FacingDirection is a unit enum → bare string in rmp_serde
|
||||||
|
|||||||
Reference in New Issue
Block a user