Critical fixes from Hoshe review: 1. Race condition: defer TCP connect to _process() with retry logic (MAX_CONNECT_RETRIES=20, 100ms interval) so server has time to bind. 2. Buffer corruption: disconnect on oversized message instead of clearing valid buffered data (_corrupt flag, fail-safe). 3. Silent input drop: send_input() returns Error so callers can detect encode/validation failures. Warnings addressed: - ServerProcess validates server_path exists before spawning - SIGKILL and health check TODOs documented for future work - Diagonal keybindings documented as intentional deferral - send_message uses single put_data() call (no partial write risk) - Static frame helpers documented as D-030 Layer 2 test-only New tests (36 total, up from 33): - Partial read scenario (chunked TCP delivery) - Multi-message sequential decode (exercises buffer corruption fix) - send_input error return on invalid action Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
56 lines
1.8 KiB
GDScript
56 lines
1.8 KiB
GDScript
extends Node
|
|
|
|
# Semantic actions — NO raw key codes cross the bridge
|
|
# Diagonal directions registered in project.godot with empty event arrays (intentional).
|
|
# Keybindings deferred until input design is finalized — likely numpad or composite WASD.
|
|
enum Action {
|
|
MOVE_NORTH, MOVE_NORTHEAST, MOVE_EAST, MOVE_SOUTHEAST,
|
|
MOVE_SOUTH, MOVE_SOUTHWEST, MOVE_WEST, MOVE_NORTHWEST,
|
|
INTERACT, USE_PERCEPTION_MODE, OPEN_MENU, PAUSE
|
|
}
|
|
|
|
var input_queue: Array[Dictionary] = []
|
|
|
|
func _unhandled_input(event: InputEvent) -> void:
|
|
var action: Action = -1
|
|
|
|
# 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
|
|
elif event.is_action_pressed("move_northeast"):
|
|
action = Action.MOVE_NORTHEAST
|
|
elif event.is_action_pressed("move_east"):
|
|
action = Action.MOVE_EAST
|
|
elif event.is_action_pressed("move_southeast"):
|
|
action = Action.MOVE_SOUTHEAST
|
|
elif event.is_action_pressed("move_south"):
|
|
action = Action.MOVE_SOUTH
|
|
elif event.is_action_pressed("move_southwest"):
|
|
action = Action.MOVE_SOUTHWEST
|
|
elif event.is_action_pressed("move_west"):
|
|
action = Action.MOVE_WEST
|
|
elif event.is_action_pressed("move_northwest"):
|
|
action = Action.MOVE_NORTHWEST
|
|
elif event.is_action_pressed("interact"):
|
|
action = Action.INTERACT
|
|
elif event.is_action_pressed("perception_mode"):
|
|
action = Action.USE_PERCEPTION_MODE
|
|
elif event.is_action_pressed("open_menu"):
|
|
action = Action.OPEN_MENU
|
|
elif event.is_action_pressed("pause"):
|
|
action = Action.PAUSE
|
|
|
|
# Queue the action if valid
|
|
if action != -1:
|
|
input_queue.append({
|
|
"action": action,
|
|
"timestamp_msec": Time.get_ticks_msec()
|
|
})
|
|
get_viewport().set_input_as_handled()
|
|
|
|
func flush_queue() -> Array[Dictionary]:
|
|
var queue = input_queue.duplicate()
|
|
input_queue.clear()
|
|
return queue
|