feat(client): sync protocol to v8 — dialogue_response + Interact encoding
Bump PROTOCOL_VERSION from 7 to 8 to match server. Three changes:
1. Add dialogue_response field decoding (DialogueResponseEvent with
line_id, text, speaker_entity_id) from server #305/D-028.
2. Fix Interact encoding: server changed PlayerAction::Interact from
unit variant to struct variant with {target_entity_id, verb}.
Extract _encode_action() helper to handle this consistently.
3. Update all test assertions that checked version=7 or expected
Interact as a bare string.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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 = 7
|
||||
const PROTOCOL_VERSION: int = 8
|
||||
|
||||
|
||||
# -- Decode: bytes from server → GDScript types --------------------------------
|
||||
@@ -169,6 +169,17 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
|
||||
"options": dialogue_options,
|
||||
}
|
||||
|
||||
# v8: dialogue_response (#305, D-028) — NPC's spoken dialogue line from server
|
||||
# Separate from current_dialogue (client-side rich dialogue state).
|
||||
var dialogue_response: Variant = null
|
||||
var raw_dr: Variant = raw.get("dialogue_response")
|
||||
if raw_dr is Dictionary and raw_dr.has("text"):
|
||||
dialogue_response = {
|
||||
"line_id": str(raw_dr.get("line_id", "")),
|
||||
"text": str(raw_dr["text"]),
|
||||
"speaker_entity_id": int(raw_dr.get("speaker_entity_id", -1)),
|
||||
}
|
||||
|
||||
return {
|
||||
"tick": tick,
|
||||
"entities": entities,
|
||||
@@ -182,6 +193,7 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant:
|
||||
"nearby_interactions": nearby_interactions,
|
||||
"current_monologue": current_monologue,
|
||||
"current_dialogue": current_dialogue,
|
||||
"dialogue_response": dialogue_response,
|
||||
"pending_recognitions": pending_recognitions,
|
||||
}
|
||||
|
||||
@@ -293,13 +305,7 @@ static func _decode_enum_variant(raw) -> Dictionary:
|
||||
## "Interact", "UsePerceptionMode", "Pause", "Unpause"
|
||||
## action_data: null for unit variants, String for UsePerceptionMode
|
||||
static func encode_player_input(tick: int, action_name: String, action_data: Variant = null) -> PackedByteArray:
|
||||
var action_value: Variant
|
||||
if action_data != null:
|
||||
# Data variant → single-element map
|
||||
action_value = { action_name: action_data }
|
||||
else:
|
||||
# Unit variant → bare string
|
||||
action_value = action_name
|
||||
var action_value: Variant = _encode_action(action_name, action_data)
|
||||
|
||||
var input := {
|
||||
"tick": tick,
|
||||
@@ -322,14 +328,9 @@ static func encode_player_inputs(inputs: Array) -> PackedByteArray:
|
||||
for input in inputs:
|
||||
var action_name: String = input["action_name"]
|
||||
var action_data: Variant = input.get("action_data")
|
||||
var action_value: Variant
|
||||
if action_data != null:
|
||||
action_value = { action_name: action_data }
|
||||
else:
|
||||
action_value = action_name
|
||||
wire_inputs.append({
|
||||
"tick": input["tick"],
|
||||
"action": action_value,
|
||||
"action": _encode_action(action_name, action_data),
|
||||
})
|
||||
|
||||
var result = Messagepack.encode(wire_inputs)
|
||||
@@ -340,6 +341,18 @@ static func encode_player_inputs(inputs: Array) -> PackedByteArray:
|
||||
return result.value
|
||||
|
||||
|
||||
## Encode a PlayerAction for the wire.
|
||||
## Struct variants (Interact) always need their fields even when null.
|
||||
## Unit variants (MoveNorth, Pause, etc.) encode as bare strings.
|
||||
static func _encode_action(action_name: String, action_data: Variant) -> Variant:
|
||||
if action_data != null:
|
||||
return { action_name: action_data }
|
||||
# Interact is a struct variant — server expects named fields, not a bare string
|
||||
if action_name == "Interact":
|
||||
return { "Interact": { "target_entity_id": null, "verb": null } }
|
||||
return action_name
|
||||
|
||||
|
||||
## Decode a PlayerInput from MessagePack bytes (used in tests / echo scenarios).
|
||||
## Returns { "tick": int, "action": { "variant": String, "data": Variant } } or null.
|
||||
static func decode_player_input(bytes: PackedByteArray) -> Variant:
|
||||
|
||||
Reference in New Issue
Block a user