Adapt game clients to the unified WebSocket input stream.

Replace separate accel/tap push handling with input messages, set_input_stream, and a single set_stream on port 8081.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-31 13:47:41 +02:00
co-authored by Cursor
parent 440b49c889
commit 70e66f4d60
7 changed files with 219 additions and 268 deletions
+76 -27
View File
@@ -20,8 +20,11 @@ var _velocity_x := 0.0
var _accel := Vector3i.ZERO
var _state := GameState.CALIBRATION
var _calibration := AccelCalibration.new()
var _client_id := 0
var _stream_ready := false
const WS_URL := "ws://localhost:9090/ws"
const WS_URL := "ws://localhost:8081/ws"
const STREAM_INTERVAL_MS := 16
const MENU_SCENE := "res://scenes/menu.tscn"
const MAX_SPEED := 900.0
const FRICTION := 0.9
@@ -53,9 +56,14 @@ func _ready() -> void:
func _return_to_menu() -> void:
_disable_input_stream()
get_tree().change_scene_to_file(MENU_SCENE)
func _exit_tree() -> void:
_disable_input_stream()
func _physics_process(delta: float) -> void:
_socket.poll()
_update_connection_status()
@@ -63,7 +71,7 @@ func _physics_process(delta: float) -> void:
if _socket.get_ready_state() == WebSocketPeer.STATE_OPEN:
while _socket.get_available_packet_count() > 0:
var packet := _socket.get_packet().get_string_from_utf8()
_handle_accel_message(packet)
_handle_message(packet)
if _state == GameState.CALIBRATION:
if calibration_overlay.is_active():
@@ -173,38 +181,79 @@ func _update_connection_status() -> void:
_socket.connect_to_url(WS_URL)
func _handle_accel_message(text: String) -> void:
func _send(payload: Dictionary) -> void:
if _socket.get_ready_state() != WebSocketPeer.STATE_OPEN:
return
_socket.send_text(JSON.stringify(payload))
func _disable_input_stream() -> void:
if _socket.get_ready_state() != WebSocketPeer.STATE_OPEN:
return
_send({"type": "set_stream", "enable": false, "interval_ms": STREAM_INTERVAL_MS})
if _client_id > 0:
_send({"type": "set_input_stream", "client_id": _client_id, "enable": false})
_stream_ready = false
func _enable_input_stream() -> void:
if _client_id <= 0:
return
_send({"type": "set_input_stream", "client_id": _client_id, "enable": true})
_send({"type": "set_stream", "enable": true, "interval_ms": STREAM_INTERVAL_MS})
_stream_ready = true
func _handle_message(text: String) -> void:
var data = JSON.parse_string(text)
if typeof(data) != TYPE_DICTIONARY:
return
if data.get("type") != "accel" or not data.get("success", false):
match data.get("type", ""):
"hello":
_send({"type": "list_clients"})
"client_list":
_on_client_list(data)
"input":
_on_input(data)
func _on_client_list(data: Dictionary) -> void:
if not data.get("success", false):
return
var parsed: Variant = _parse_accel_vector(data)
if parsed == null:
for entry in data.get("clients", []):
if typeof(entry) != TYPE_DICTIONARY:
continue
if not entry.get("available", false):
continue
var cid := int(entry.get("id", 0))
if cid > 0:
_client_id = cid
break
if _client_id > 0 and not _stream_ready:
_enable_input_stream()
func _on_input(data: Dictionary) -> void:
if not data.get("success", false):
return
_accel = parsed as Vector3i
func _parse_accel_vector(data: Dictionary) -> Variant:
var source: Variant = _accel_fields_dict(data)
if source == null:
return null
return Vector3i(
_to_int(source.get("x")),
_to_int(source.get("y")),
_to_int(source.get("z"))
)
func _accel_fields_dict(data: Dictionary) -> Variant:
if data.has("x") and data.has("y") and data.has("z"):
return data
for key in ["accel", "values", "data", "payload"]:
var nested: Variant = data.get(key)
if nested is Dictionary and nested.has("x") and nested.has("y") and nested.has("z"):
return nested
return null
for client in data.get("clients", []):
if typeof(client) != TYPE_DICTIONARY:
continue
var cid := int(client.get("client_id", 0))
if _client_id > 0 and cid != _client_id:
continue
if not client.get("valid", false):
continue
_accel = Vector3i(
_to_int(client.get("x")),
_to_int(client.get("y")),
_to_int(client.get("z"))
)
return
func _to_int(value: Variant) -> int: