feat(client): protocol v14 decoders and game state fields
Decode poi_list, examine_result, and player_knowledge from ObserverSnapshot. Add GameState.discovered_pois, current_examine_result, and player_knowledge fields populated from snapshot apply handlers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -70,6 +70,21 @@ var dialogue_response: Variant = null # {line_id, text, speaker_entity_id}
|
||||
var conversation_events: Array = [] # [{speaker_id, target_id, speaker_name, target_name, occluded_line}]
|
||||
var conversation_ended: Array = [] # [{speaker_id, target_id}]
|
||||
|
||||
# v10 fields (#151, D-013): Discovered POIs from server (#148/#149).
|
||||
# Format: [{poi_id, name, x, y, z, category}]. Persists between snapshots unless
|
||||
# server explicitly sends an empty array (cleared locations are not typical in v0.1).
|
||||
# Populated from snapshot "poi_list" field — only updated when field present.
|
||||
var discovered_pois: Array = []
|
||||
|
||||
# v14 fields (#174, #242): Character-filtered examine result.
|
||||
# {entity_id, text, confidence} or null. Auto-dismisses on client after 4-6 seconds.
|
||||
var current_examine_result: Variant = null
|
||||
|
||||
# v14 fields (#264, D-041): Player knowledge graph dump for journal panel.
|
||||
# {entities: [{entity_id, name, confidence, source, state, relationship, last_observed_tick}],
|
||||
# facts: [{fact_id, confidence, source, state, acquired_tick}]}
|
||||
var player_knowledge: Variant = null
|
||||
|
||||
# #126, D-018: Medium-range sound events for fog-edge directional indicators.
|
||||
# Format: [{x, y, event_type, range_category}] — server sends current medium events per tick.
|
||||
var medium_sound_events: Array = []
|
||||
@@ -240,6 +255,25 @@ func apply_snapshot(snapshot: Dictionary) -> void:
|
||||
medium_sound_events = []
|
||||
close_sound_events = []
|
||||
|
||||
# v10: discovered_pois (#151, D-013) — server sends POIs discovered by the player.
|
||||
# Accepts "discovered_pois" or "poi_list" key — both map to the same client field.
|
||||
# Only update if the field is present — absence means "no change since last tick".
|
||||
if snapshot.has("discovered_pois") and snapshot.discovered_pois is Array:
|
||||
discovered_pois = snapshot.discovered_pois
|
||||
elif snapshot.has("poi_list") and snapshot.poi_list is Array:
|
||||
discovered_pois = snapshot.poi_list
|
||||
|
||||
# v14: examine_result (#174, #242) — character-filtered observation from Examine verb.
|
||||
if snapshot.has("examine_result") and snapshot.examine_result is Dictionary:
|
||||
current_examine_result = snapshot.examine_result
|
||||
else:
|
||||
current_examine_result = null
|
||||
|
||||
# v14: player_knowledge (#264, D-041) — partial KG dump for journal panel.
|
||||
# Only update when field is present (null means no change, server sends when KG changes).
|
||||
if snapshot.has("player_knowledge") and snapshot.player_knowledge is Dictionary:
|
||||
player_knowledge = snapshot.player_knowledge
|
||||
|
||||
# D-073 (#529): O(1) zone_id lookup. Build coord→tile dict from member visible_tiles
|
||||
# (populated above from either "tiles" test-mode key or "visible_tiles" live key).
|
||||
# Must use the member var, not snapshot.visible_tiles, so test mode is covered.
|
||||
|
||||
@@ -11,7 +11,7 @@ class_name Protocol
|
||||
|
||||
## Protocol version — must match server PROTOCOL_VERSION in bridge/types.rs.
|
||||
## Reject snapshots where version != this value.
|
||||
const PROTOCOL_VERSION: int = 13
|
||||
const PROTOCOL_VERSION: int = 14
|
||||
|
||||
|
||||
# -- Decode: bytes from server → GDScript types --------------------------------
|
||||
@@ -206,6 +206,70 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
|
||||
"target_id": int(raw_end.get("target_id", 0)),
|
||||
})
|
||||
|
||||
# v14: poi_list (#151) — discovered POIs for minimap rendering.
|
||||
# Each entry: {poi_id, name, x, y, z, category}. Positions in sim tile coords.
|
||||
var poi_list: Array = []
|
||||
var raw_pois: Variant = raw.get("poi_list")
|
||||
if raw_pois is Array:
|
||||
for raw_poi in raw_pois:
|
||||
if raw_poi is Dictionary and raw_poi.has("poi_id") and raw_poi.has("x") and raw_poi.has("y"):
|
||||
poi_list.append({
|
||||
"poi_id": str(raw_poi["poi_id"]),
|
||||
"name": str(raw_poi.get("name", "")),
|
||||
"x": int(raw_poi["x"]),
|
||||
"y": int(raw_poi["y"]),
|
||||
"z": int(raw_poi.get("z", 0)),
|
||||
"category": str(raw_poi.get("category", "Location")),
|
||||
})
|
||||
|
||||
# v14: examine_result (#174, #242) — character-filtered observation text.
|
||||
# {entity_id, text, confidence} or null. Auto-dismisses on client after 4-6 seconds.
|
||||
var examine_result: Variant = null
|
||||
var raw_examine: Variant = raw.get("examine_result")
|
||||
if raw_examine is Dictionary and raw_examine.has("text"):
|
||||
examine_result = {
|
||||
"entity_id": int(raw_examine.get("entity_id", 0)),
|
||||
"text": str(raw_examine["text"]),
|
||||
"confidence": str(raw_examine.get("confidence", "KnowsOf")),
|
||||
}
|
||||
|
||||
# v14: player_knowledge (#264, D-041) — partial KG dump for journal panel.
|
||||
# {entities: [{entity_id, name, confidence, source, state, relationship, last_observed_tick}],
|
||||
# facts: [{fact_id, confidence, source, state, acquired_tick}]}
|
||||
var player_knowledge: Variant = null
|
||||
var raw_pk: Variant = raw.get("player_knowledge")
|
||||
if raw_pk is Dictionary:
|
||||
var kg_entities: Array = []
|
||||
var raw_kg_entities: Variant = raw_pk.get("entities")
|
||||
if raw_kg_entities is Array:
|
||||
for raw_ke in raw_kg_entities:
|
||||
if raw_ke is Dictionary and raw_ke.has("entity_id"):
|
||||
kg_entities.append({
|
||||
"entity_id": int(raw_ke["entity_id"]),
|
||||
"name": str(raw_ke.get("name", "Unknown")),
|
||||
"confidence": str(raw_ke.get("confidence", "Suspects")),
|
||||
"source": str(raw_ke.get("source", "")),
|
||||
"state": str(raw_ke.get("state", "Active")),
|
||||
"relationship": str(raw_ke.get("relationship", "Unknown")),
|
||||
"last_observed_tick": int(raw_ke.get("last_observed_tick", 0)),
|
||||
})
|
||||
var kg_facts: Array = []
|
||||
var raw_kg_facts: Variant = raw_pk.get("facts")
|
||||
if raw_kg_facts is Array:
|
||||
for raw_kf in raw_kg_facts:
|
||||
if raw_kf is Dictionary and raw_kf.has("fact_id"):
|
||||
kg_facts.append({
|
||||
"fact_id": str(raw_kf["fact_id"]),
|
||||
"confidence": str(raw_kf.get("confidence", "Suspects")),
|
||||
"source": str(raw_kf.get("source", "")),
|
||||
"state": str(raw_kf.get("state", "Active")),
|
||||
"acquired_tick": int(raw_kf.get("acquired_tick", 0)),
|
||||
})
|
||||
player_knowledge = {
|
||||
"entities": kg_entities,
|
||||
"facts": kg_facts,
|
||||
}
|
||||
|
||||
return {
|
||||
"tick": tick,
|
||||
"entities": entities,
|
||||
@@ -223,6 +287,9 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
|
||||
"pending_recognitions": pending_recognitions,
|
||||
"conversation_events": conversation_events,
|
||||
"conversation_ended": conversation_ended,
|
||||
"poi_list": poi_list,
|
||||
"examine_result": examine_result,
|
||||
"player_knowledge": player_knowledge,
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user