fix(client): address PR review — input bug, bounds checks, fixture tests
- Fix input_mapper double-check bug (redundant InputEventKey + pressed filter) - Add bounds checking for position arrays in entity_renderer and game_state - Make test snapshot deterministic (incrementing counter, not wall clock) - Fix tween overlap in monologue_display (cancel active tween before new one) - Extract TILE_SIZE constant from magic number 32 - Add 5 D-030 Layer 1 fixture tests for snapshot parsing (7/7 total passing) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,10 @@ func apply_snapshot(snapshot: Dictionary) -> void:
|
||||
# Parse player data
|
||||
if snapshot.has("player") and snapshot.player.has("position"):
|
||||
var pos = snapshot.player.position
|
||||
player_position = Vector2(pos[0], pos[1])
|
||||
if pos is Array and pos.size() >= 2:
|
||||
player_position = Vector2(pos[0], pos[1])
|
||||
else:
|
||||
push_warning("GameState: malformed player position in snapshot")
|
||||
|
||||
# Parse entities
|
||||
if snapshot.has("entities"):
|
||||
|
||||
@@ -9,40 +9,26 @@ enum Action {
|
||||
var input_queue: Array[Dictionary] = []
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
# Only process key press events (not releases or repeats)
|
||||
if not event is InputEventKey:
|
||||
return
|
||||
if not event.pressed or event.echo:
|
||||
return
|
||||
|
||||
var action: Action = -1
|
||||
var action_name: String = ""
|
||||
|
||||
# Map input actions to semantic Action enum
|
||||
# is_action_pressed handles press detection for all input types (key, gamepad, etc.)
|
||||
if event.is_action_pressed("move_north"):
|
||||
action = Action.MOVE_NORTH
|
||||
action_name = "move_north"
|
||||
elif event.is_action_pressed("move_south"):
|
||||
action = Action.MOVE_SOUTH
|
||||
action_name = "move_south"
|
||||
elif event.is_action_pressed("move_east"):
|
||||
action = Action.MOVE_EAST
|
||||
action_name = "move_east"
|
||||
elif event.is_action_pressed("move_west"):
|
||||
action = Action.MOVE_WEST
|
||||
action_name = "move_west"
|
||||
elif event.is_action_pressed("interact"):
|
||||
action = Action.INTERACT
|
||||
action_name = "interact"
|
||||
elif event.is_action_pressed("perception_mode"):
|
||||
action = Action.USE_PERCEPTION_MODE
|
||||
action_name = "perception_mode"
|
||||
elif event.is_action_pressed("open_menu"):
|
||||
action = Action.OPEN_MENU
|
||||
action_name = "open_menu"
|
||||
elif event.is_action_pressed("pause"):
|
||||
action = Action.PAUSE
|
||||
action_name = "pause"
|
||||
|
||||
# Queue the action if valid
|
||||
if action != -1:
|
||||
|
||||
@@ -5,6 +5,7 @@ enum ConnectionState { DISCONNECTED, CONNECTING, CONNECTED, ERROR }
|
||||
|
||||
var state: ConnectionState = ConnectionState.DISCONNECTED
|
||||
var test_mode: bool = true # Enable test mode for development without Rust server
|
||||
var _test_tick: int = 0
|
||||
|
||||
# Signals
|
||||
signal connection_state_changed(old_state: ConnectionState, new_state: ConnectionState)
|
||||
@@ -54,10 +55,11 @@ func poll_snapshot() -> Variant:
|
||||
# TODO: Actual polling logic when IPC/MessagePack is implemented
|
||||
return null
|
||||
|
||||
# Hardcoded test snapshot for development
|
||||
# Hardcoded test snapshot for development (deterministic per D-010 principle 4)
|
||||
func _test_snapshot() -> Dictionary:
|
||||
_test_tick += 1
|
||||
return {
|
||||
"tick": Time.get_ticks_msec() / 100, # Increment over time for testing
|
||||
"tick": _test_tick,
|
||||
"player": {
|
||||
"position": [10, 10],
|
||||
"health": 100
|
||||
|
||||
@@ -3,6 +3,8 @@ extends Node2D
|
||||
# Entity renderer — manages entity sprites under the Entities node
|
||||
# Creates/updates/removes Sprite2D children based on entity data
|
||||
|
||||
const TILE_SIZE: int = 32
|
||||
|
||||
var entity_nodes: Dictionary = {} # id -> Node2D mapping
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -63,7 +65,10 @@ func _update_entity_node(entity_id: int, entity_data: Dictionary) -> void:
|
||||
# Update position
|
||||
if entity_data.has("position"):
|
||||
var pos = entity_data.position
|
||||
entity_node.position = Vector2(pos[0] * 32, pos[1] * 32) # 32px grid
|
||||
if pos is Array and pos.size() >= 2:
|
||||
entity_node.position = Vector2(pos[0] * TILE_SIZE, pos[1] * TILE_SIZE)
|
||||
else:
|
||||
push_warning("EntityRenderer: malformed position for entity %s" % entity_id)
|
||||
|
||||
# Remove an entity node
|
||||
func _remove_entity_node(entity_id: int) -> void:
|
||||
|
||||
Reference in New Issue
Block a user