From ea9cf554c6dde6afa41ff294f50200e977237c1a Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Fri, 13 Feb 2026 02:07:29 +0100 Subject: [PATCH] fix(client): decode tile_kind and fix entity alignment (#412) Protocol decoder now reads tile_kind from VisibleTile and maps it to the client's tile type string (floor/wall/door/object). GameState falls back to visible_tiles when the test-mode tiles array is absent, enabling live server tile rendering. Fix entity-to-tile alignment: server sends tile-center render coords (tile 16 -> 16.5) but entity renderer was using raw floats, placing entities half a tile off. Now floors the coords to get the tile index. Co-Authored-By: Claude Opus 4.6 --- client/scripts/autoloads/game_state.gd | 8 ++++++++ client/scripts/protocol/protocol.gd | 8 +++++++- client/scripts/rendering/entity_renderer.gd | 7 ++++--- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/client/scripts/autoloads/game_state.gd b/client/scripts/autoloads/game_state.gd index 5a04eea3f..0d9667ae2 100644 --- a/client/scripts/autoloads/game_state.gd +++ b/client/scripts/autoloads/game_state.gd @@ -43,8 +43,16 @@ func apply_snapshot(snapshot: Dictionary) -> void: push_warning("GameState: no Player entity found in %d entities" % [ visible_entities.size()]) + # Tiles for rendering: test mode sends "tiles", live server sends tile data in "visible_tiles" if snapshot.has("tiles"): visible_tiles = snapshot.tiles + elif snapshot.has("visible_tiles") and snapshot.visible_tiles is Array and snapshot.visible_tiles.size() > 0: + # Live server: visible_tiles now includes type from tile_kind field + var has_type := false + if snapshot.visible_tiles.size() > 0 and snapshot.visible_tiles[0] is Dictionary: + has_type = snapshot.visible_tiles[0].has("type") + if has_type: + visible_tiles = snapshot.visible_tiles if snapshot.has("visible_positions"): visible_positions.clear() diff --git a/client/scripts/protocol/protocol.gd b/client/scripts/protocol/protocol.gd index 2ee9399e6..bb69783bc 100644 --- a/client/scripts/protocol/protocol.gd +++ b/client/scripts/protocol/protocol.gd @@ -63,7 +63,7 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant: if raw_facing is String: player_facing = raw_facing - # visible_tiles: Array of {x, y, z, visibility} + # visible_tiles: Array of {x, y, z, visibility, tile_kind} var visible_tiles: Array = [] var raw_vtiles: Variant = raw.get("visible_tiles") if raw_vtiles is Array: @@ -77,6 +77,12 @@ static func decode_snapshot(bytes: PackedByteArray) -> Variant: var vis: Variant = raw_tile.get("visibility") if vis is String: tile_entry["visibility"] = vis + # tile_kind: Floor/Wall/Door/Object — map to client tile type strings + var kind: Variant = raw_tile.get("tile_kind") + if kind is String: + tile_entry["type"] = kind.to_lower() + else: + tile_entry["type"] = "floor" visible_tiles.append(tile_entry) # v4: nearby_interactions (#404/#405) diff --git a/client/scripts/rendering/entity_renderer.gd b/client/scripts/rendering/entity_renderer.gd index cd6a439a5..489c04da1 100644 --- a/client/scripts/rendering/entity_renderer.gd +++ b/client/scripts/rendering/entity_renderer.gd @@ -71,11 +71,12 @@ func _update_entity_node(entity_id: int, entity_data: Dictionary) -> void: var entity_node = entity_nodes[entity_id] - # Update position from x, y fields (Protocol format), centered within tile + # Update position from x, y fields (Protocol format), centered within tile. + # Server sends tile-center coords (tile 16 → 16.5), floor to get tile index. if entity_data.has("x") and entity_data.has("y"): entity_node.position = Vector2( - entity_data.x * TILE_SIZE + ENTITY_OFFSET, - entity_data.y * TILE_SIZE + ENTITY_OFFSET + floorf(entity_data.x) * TILE_SIZE + ENTITY_OFFSET, + floorf(entity_data.y) * TILE_SIZE + ENTITY_OFFSET ) # v2: Peripheral vision dimming (D-015)