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:
@@ -121,7 +121,7 @@ func _finish() -> void:
|
||||
|
||||
|
||||
func _show_waiting() -> void:
|
||||
_instruction = "Warte auf Verbindung zu localhost:9090…"
|
||||
_instruction = "Warte auf Verbindung zu localhost:8081…"
|
||||
_hint_label.text = _instruction + "\n(Oder „Kalibrierung starten“ ohne Verbindung)"
|
||||
|
||||
|
||||
|
||||
+12
-10
@@ -62,7 +62,7 @@ func _send(payload: Dictionary) -> void:
|
||||
func _cleanup_streams() -> void:
|
||||
if _socket.get_ready_state() != WebSocketPeer.STATE_OPEN:
|
||||
return
|
||||
_send({"type": "set_tap_stream", "enable": false, "interval_ms": STREAM_INTERVAL_MS})
|
||||
_send({"type": "set_stream", "enable": false, "interval_ms": STREAM_INTERVAL_MS})
|
||||
for cid in _pod_ids:
|
||||
_send({
|
||||
"type": "set_tap_notify",
|
||||
@@ -106,8 +106,8 @@ func _handle_message(text: String) -> void:
|
||||
_send({"type": "list_clients"})
|
||||
"client_list":
|
||||
_on_client_list(data)
|
||||
"tap":
|
||||
_on_tap(data)
|
||||
"input":
|
||||
_on_input(data)
|
||||
|
||||
|
||||
func _on_client_list(data: Dictionary) -> void:
|
||||
@@ -155,7 +155,7 @@ func _start_round() -> void:
|
||||
for cid in _pod_ids:
|
||||
_send_led_digit(cid, int(_pod_digits[cid]))
|
||||
|
||||
_enable_tap_stream()
|
||||
_enable_input_stream()
|
||||
_round_start_ms = Time.get_ticks_msec()
|
||||
_set_phase(Phase.PLAYING, "%d Pods bereit" % _pod_ids.size())
|
||||
target_label.text = str(_target_digit)
|
||||
@@ -164,7 +164,7 @@ func _start_round() -> void:
|
||||
hint_label.text = ""
|
||||
|
||||
|
||||
func _enable_tap_stream() -> void:
|
||||
func _enable_input_stream() -> void:
|
||||
for cid in _pod_ids:
|
||||
_send({
|
||||
"type": "set_tap_notify",
|
||||
@@ -173,17 +173,19 @@ func _enable_tap_stream() -> void:
|
||||
"double_tap": false,
|
||||
"triple": false,
|
||||
})
|
||||
_send({"type": "set_tap_stream", "enable": true, "interval_ms": STREAM_INTERVAL_MS})
|
||||
_send({"type": "set_stream", "enable": true, "interval_ms": STREAM_INTERVAL_MS})
|
||||
|
||||
|
||||
func _on_tap(data: Dictionary) -> void:
|
||||
func _on_input(data: Dictionary) -> void:
|
||||
if _phase != Phase.PLAYING or not data.get("success", false):
|
||||
return
|
||||
|
||||
for event in data.get("events", []):
|
||||
if typeof(event) != TYPE_DICTIONARY:
|
||||
for client in data.get("clients", []):
|
||||
if typeof(client) != TYPE_DICTIONARY:
|
||||
continue
|
||||
var cid := int(event.get("client_id", 0))
|
||||
if str(client.get("tap_kind", "none")) == "none":
|
||||
continue
|
||||
var cid := int(client.get("client_id", 0))
|
||||
if not _pod_digits.has(cid):
|
||||
continue
|
||||
if cid == _target_cid:
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
extends Control
|
||||
|
||||
const MENU_SCENE := "res://scenes/menu.tscn"
|
||||
const WS_URL := "ws://localhost:9090/ws"
|
||||
const WS_URL := "ws://localhost:8081/ws"
|
||||
|
||||
@onready var back_button: Button = $UiLayer/BackButton
|
||||
@onready var ws_url_label: Label = $UiLayer/Panel/WSUrlLabel
|
||||
|
||||
+32
-57
@@ -79,7 +79,7 @@ func _start_stream() -> void:
|
||||
continue
|
||||
|
||||
var accel_on: bool = ui["accel_cb"].button_pressed
|
||||
_send({"type": "set_accel_stream", "client_id": cid, "enable": accel_on})
|
||||
_send({"type": "set_input_stream", "client_id": cid, "enable": accel_on})
|
||||
if accel_on:
|
||||
want_accel = true
|
||||
|
||||
@@ -97,24 +97,23 @@ func _start_stream() -> void:
|
||||
if tap_on:
|
||||
want_tap = true
|
||||
|
||||
_send({"type": "set_stream", "enable": want_accel, "interval_ms": _interval_ms()})
|
||||
_send({"type": "set_tap_stream", "enable": want_tap, "interval_ms": _interval_ms()})
|
||||
var want_input := want_accel or want_tap
|
||||
_send({"type": "set_stream", "enable": want_input, "interval_ms": _interval_ms()})
|
||||
|
||||
_streaming = true
|
||||
start_stream_btn.disabled = true
|
||||
stop_stream_btn.disabled = false
|
||||
_log("Stream gestartet (accel=%s, tap=%s)" % [want_accel, want_tap])
|
||||
_log("Stream gestartet (input=%s, accel=%s, tap=%s)" % [want_input, want_accel, want_tap])
|
||||
|
||||
|
||||
func _stop_stream() -> void:
|
||||
_send({"type": "set_stream", "enable": false, "interval_ms": _interval_ms()})
|
||||
_send({"type": "set_tap_stream", "enable": false, "interval_ms": _interval_ms()})
|
||||
|
||||
for cid in _client_ui:
|
||||
var ui: Dictionary = _client_ui[cid]
|
||||
if not ui.get("available", false):
|
||||
continue
|
||||
_send({"type": "set_accel_stream", "client_id": cid, "enable": false})
|
||||
_send({"type": "set_input_stream", "client_id": cid, "enable": false})
|
||||
_send({
|
||||
"type": "set_tap_notify",
|
||||
"client_id": cid,
|
||||
@@ -180,7 +179,7 @@ func _populate_clients(clients: Array) -> void:
|
||||
|
||||
var accel_cb := CheckBox.new()
|
||||
accel_cb.text = "Accel Stream"
|
||||
accel_cb.button_pressed = entry.get("accel_stream", false)
|
||||
accel_cb.button_pressed = entry.get("input_stream", false)
|
||||
accel_cb.disabled = not available
|
||||
vbox.add_child(accel_cb)
|
||||
|
||||
@@ -361,7 +360,6 @@ func _populate_clients(clients: Array) -> void:
|
||||
"led_digit_row": led_digit_row,
|
||||
"led_blink_row": led_blink_row,
|
||||
"values_label": values_label,
|
||||
"last_tap": "",
|
||||
}
|
||||
_update_led_fields(cid)
|
||||
|
||||
@@ -406,10 +404,8 @@ func _handle_message(text: String) -> void:
|
||||
_on_hello(data)
|
||||
"client_list":
|
||||
_on_client_list(data)
|
||||
"accel":
|
||||
_on_accel(data)
|
||||
"tap":
|
||||
_on_tap(data)
|
||||
"input":
|
||||
_on_input(data)
|
||||
"led_ring_status":
|
||||
_log("← LED #%s: %s" % [data.get("client_id", "?"), "OK" if data.get("success", false) else data.get("error", "?")])
|
||||
_:
|
||||
@@ -431,9 +427,9 @@ func _on_client_list(data: Dictionary) -> void:
|
||||
_populate_clients(data.get("clients", []))
|
||||
|
||||
|
||||
func _on_accel(data: Dictionary) -> void:
|
||||
func _on_input(data: Dictionary) -> void:
|
||||
if not data.get("success", false):
|
||||
stream_output.text = "accel FEHLER: %s" % data.get("error", "?")
|
||||
stream_output.text = "input FEHLER: %s" % data.get("error", "?")
|
||||
return
|
||||
|
||||
var summary: PackedStringArray = []
|
||||
@@ -445,54 +441,33 @@ func _on_accel(data: Dictionary) -> void:
|
||||
continue
|
||||
|
||||
var ui: Dictionary = _client_ui[cid]
|
||||
var tap_part: String = ui.get("last_tap", "")
|
||||
var lines: PackedStringArray = []
|
||||
if client.get("valid", false):
|
||||
var accel_text := "x=%d y=%d z=%d (age %sms)" % [
|
||||
int(client.get("x", 0)),
|
||||
int(client.get("y", 0)),
|
||||
int(client.get("z", 0)),
|
||||
str(client.get("age_ms", "?")),
|
||||
]
|
||||
ui["values_label"].text = accel_text + ("\n" + tap_part if tap_part else "")
|
||||
summary.append("#%d: %s" % [cid, accel_text])
|
||||
lines.append(
|
||||
"x=%d y=%d z=%d (age %sms)" % [
|
||||
int(client.get("x", 0)),
|
||||
int(client.get("y", 0)),
|
||||
int(client.get("z", 0)),
|
||||
str(client.get("accel_age_ms", "?")),
|
||||
]
|
||||
)
|
||||
|
||||
var tap_kind := str(client.get("tap_kind", "none"))
|
||||
if tap_kind != "none":
|
||||
var tap_text := "tap: %s (age %sms)" % [tap_kind, str(client.get("tap_age_ms", "?"))]
|
||||
lines.append(tap_text)
|
||||
_flash_client_panel(cid)
|
||||
|
||||
if lines.is_empty():
|
||||
ui["values_label"].text = "—"
|
||||
else:
|
||||
ui["values_label"].text = "accel: —" + ("\n" + tap_part if tap_part else "")
|
||||
ui["values_label"].text = "\n".join(lines)
|
||||
summary.append("#%d: %s" % [cid, " · ".join(lines)])
|
||||
|
||||
if summary.is_empty():
|
||||
stream_output.text = "accel (keine gültigen Samples)"
|
||||
stream_output.text = "input (keine Daten)"
|
||||
else:
|
||||
stream_output.text = "accel\n" + "\n".join(summary)
|
||||
|
||||
|
||||
func _on_tap(data: Dictionary) -> void:
|
||||
if not data.get("success", false):
|
||||
return
|
||||
|
||||
var summary: PackedStringArray = []
|
||||
for event in data.get("events", []):
|
||||
if typeof(event) != TYPE_DICTIONARY:
|
||||
continue
|
||||
var cid := int(event.get("client_id", 0))
|
||||
if not _client_ui.has(cid):
|
||||
continue
|
||||
|
||||
var tap_text := "tap: %s (age %sms)" % [str(event.get("kind", "?")), str(event.get("age_ms", "?"))]
|
||||
var ui: Dictionary = _client_ui[cid]
|
||||
ui["last_tap"] = tap_text
|
||||
|
||||
var existing: String = ui["values_label"].text
|
||||
if existing == "—" or existing.begins_with("accel: —"):
|
||||
ui["values_label"].text = tap_text
|
||||
elif "\n" in existing:
|
||||
ui["values_label"].text = existing.split("\n", false, 1)[0] + "\n" + tap_text
|
||||
else:
|
||||
ui["values_label"].text = existing + "\n" + tap_text
|
||||
|
||||
summary.append("#%d: %s" % [cid, tap_text])
|
||||
_flash_client_panel(cid)
|
||||
|
||||
if not summary.is_empty():
|
||||
stream_output.text = "tap\n" + "\n".join(summary)
|
||||
stream_output.text = "input\n" + "\n".join(summary)
|
||||
|
||||
|
||||
func _set_spinbox_enabled(spin: SpinBox, enabled: bool) -> void:
|
||||
|
||||
+76
-27
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user