Files
room_glitch/operator/arcade_room_operator.gd

104 lines
4.0 KiB
GDScript

extends Control
var connection: Node
var busy := false
var status: Label
var history: RichTextLabel
var prepare: Button
var start: Button
var reset: Button
var message: Label
var confirm: ConfirmationDialog
func _ready() -> void:
connection = preload("res://core/network/room_connection.gd").new()
add_child(connection)
connection.configure("operator")
var center := CenterContainer.new()
center.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
add_child(center)
var column := VBoxContainer.new()
column.custom_minimum_size = Vector2(1050, 0)
column.add_theme_constant_override("separation", 18)
center.add_child(column)
var title := Label.new()
title.text = "ARCADE ROOM CONTROL"
title.add_theme_font_size_override("font_size", 42)
column.add_child(title)
status = Label.new()
status.add_theme_font_size_override("font_size", 25)
column.add_child(status)
var row := HBoxContainer.new()
column.add_child(row)
prepare = add_button(row, "Prepare Pac-Man", func(): command("prepare"))
start = add_button(row, "Start Game", func(): command("start"))
reset = add_button(row, "Reset Cabinet…", func(): confirm.popup_centered())
confirm = ConfirmationDialog.new()
confirm.dialog_text = "Unload the current game and reset this cabinet's room session?"
confirm.confirmed.connect(func(): command("reset"))
add_child(confirm)
message = Label.new()
message.text = "Cabinet 01 quick controls • Open the controller URL in a browser for all cabinets"
column.add_child(message)
history = RichTextLabel.new()
history.custom_minimum_size = Vector2(1050, 380)
history.add_theme_font_size_override("normal_font_size", 20)
column.add_child(history)
var hint := Label.new()
hint.text = "Accepted GPIO output does not confirm physical coin delivery.\nClosing this window leaves the room controller running. Escape closes this app."
column.add_child(hint)
set_buttons(false, false, false)
var timer := Timer.new()
timer.wait_time = 1.0
timer.timeout.connect(refresh)
add_child(timer)
timer.start()
refresh()
func add_button(parent: Node, text: String, callback: Callable) -> Button:
var button := Button.new()
button.text = text
button.add_theme_font_size_override("font_size", 24)
button.pressed.connect(callback)
parent.add_child(button)
return button
func set_buttons(can_prepare: bool, can_start: bool, can_reset: bool) -> void:
prepare.disabled = not can_prepare
start.disabled = not can_start
reset.disabled = not can_reset
func display(state: Dictionary) -> void:
if state.has("error"):
status.text = "CONTROLLER UNAVAILABLE\n" + str(state.error)
set_buttons(false, false, false)
return
var pending := false
for item in state.commands:
if item.status == "queued": pending = true
var available: bool = state.online and not pending
set_buttons(available and state.phase in ["idle", "won", "lost", "needs_prepare"], available and state.phase == "ready", available)
status.text = "Cabinet 01: %s | %s\nGame: %s | GPIO mode: %s | Agent: %s\nReward: %s" % ["ONLINE" if state.online else "OFFLINE", str(state.phase).to_upper(), state.get("game", "pacman"), state.gpio, state.version, state.reward]
history.text = "EVENT HISTORY\n"
for item in state.history:
history.text += "%s %s\n" % [Time.get_datetime_string_from_unix_time(int(item.time)).replace("T", " ") + " UTC", item.message]
history.scroll_to_line(history.get_line_count())
func refresh() -> void:
if busy: return
busy = true
var state: Dictionary = await connection.post("/operator/state")
busy = false
display(state)
func command(action: String) -> void:
if busy: return
busy = true
set_buttons(false, false, false)
var payload := {"action": action, "cabinet": "cabinet_01"}
if action == "prepare": payload = {"action": "prepare_scenario", "scenario": "proof_of_concept"}
var state: Dictionary = await connection.post("/operator/command", payload)
busy = false
if state.has("error"): message.text = str(state.error)
else: message.text = "Command queued; waiting for cabinet acknowledgement"
display(state)