Expand Glitch operations hub, cabinet authoring, deployment, and RFID support

Operator hub
- Introduce Escape Gallery branding and Glitch: the Dark Machine room views
- Add cabinet illustrations, Pac-Man marquee/gameplay artwork, and waiting states
- Add device feedback panels with RFID readings, input/output states, and stale status
- Add logged operator hardware interventions with request deduplication

Room and cabinet authoring
- Add a visual custom-PCB connection editor with per-cabinet device inventory
- Support device IDs, bindings, wiring notes, input polarity, and validation
- Add physical-room label/dimension toggles and editable doorway annotations
- Preserve doorway changes through undo, save, and revert
- Expand cabinet profiles, room layout, and Glitch scenario resources

Scenarios and gameplay
- Add per-assignment game configuration and runtime feature validation
- Add timed test wins and Frogger individual-home objectives
- Add the three-cabinet timed/score/Frogger test scenario
- Add Cabinet 1 Pac-Man RFID credits, credit sound, and CREDIT 0/1 display
- Require physical Start after an accepted scan and prevent duplicate credits

Pi hardware and deployment
- Add GPIO feedback sampling and a separate multiplexed RFID helper
- Validate reader pin ownership and input/output conflicts
- Add SSH cabinet startup and Pi desktop-session service support
- Add master packaging, site setup, SSH enrollment, and staged cabinet releases
- Verify deployment manifests and support explicit activation/status/log commands

Documentation and verification
- Consolidate the root README around the current architecture and setup workflow
- Add the complete master/Pi/RFID export and deployment walkthrough
- Document network isolation, credentials, card identification, and rollback
- Add PCB, room-editor, feedback, credit, deployment, and controller tests
- Isolate protocol tests from designer-edited cabinet configurations

Known limitations
- RFID helper compilation and physical Pi commissioning remain unverified
- Fleet provisioning does not yet configure RFID-only installations completely
- Broader Pac-Man tests retain a ghost-capture assertion failure
- Staged exports must be rebuilt and checked before deploying runtime 2.3
This commit is contained in:
Jeff Luke committed 2026-10-17 14:53:54 -07:00
1 parent 705ec31e0b
commit c1b2195834
90 files changed
+4969 -456

No files matched your search

+8 -7
View File
@@ -1,11 +1,12 @@
[gd_resource type="Resource" script_class="ScenarioDefinition" format=3]
[gd_resource type="Resource" script_class="ScenarioDefinition" format=3 uid="uid://cv8oknw3dlwjk"]
[ext_resource type="Script" path="res://core/scenarios/scenario_definition.gd" id="1"]
[ext_resource type="Script" path="res://core/scenarios/scenario_assignment.gd" id="2"]
[ext_resource type="Resource" path="res://data/cabinets/cabinet_01.tres" id="3"]
[ext_resource type="Resource" path="res://data/cabinets/cabinet_02.tres" id="4"]
[ext_resource type="Resource" path="res://data/games/pacman.tres" id="5"]
[ext_resource type="Resource" path="res://data/games/galaga.tres" id="6"]
[ext_resource type="Script" uid="uid://d3pt6qa05kcnl" path="res://core/scenarios/scenario_definition.gd" id="1"]
[ext_resource type="Script" uid="uid://ibujr0ervhhq" path="res://core/scenarios/scenario_assignment.gd" id="2"]
[ext_resource type="Resource" uid="uid://cl4j1vtv388pt" path="res://data/cabinets/cabinet_01.tres" id="3"]
[ext_resource type="Script" uid="uid://lixrugm1v2d2" path="res://core/scenarios/scenario_event_mapping.gd" id="3_mhdgo"]
[ext_resource type="Resource" uid="uid://d1gyyfaaclas8" path="res://data/cabinets/cabinet_02.tres" id="4"]
[ext_resource type="Resource" uid="uid://c3v8o4nubjakg" path="res://data/games/pacman.tres" id="5"]
[ext_resource type="Resource" uid="uid://cnfhiky5834pw" path="res://data/games/galaga.tres" id="6"]
[sub_resource type="Resource" id="First"]
script = ExtResource("2")
+44
View File
@@ -0,0 +1,44 @@
[gd_resource type="Resource" script_class="ScenarioDefinition" format=3 uid="uid://crijr0r2ikxs1"]
[ext_resource type="Script" uid="uid://ibujr0ervhhq" path="res://core/scenarios/scenario_assignment.gd" id="1_40f70"]
[ext_resource type="Resource" uid="uid://cl4j1vtv388pt" path="res://data/cabinets/cabinet_01.tres" id="2_nsmc3"]
[ext_resource type="Script" uid="uid://lixrugm1v2d2" path="res://core/scenarios/scenario_event_mapping.gd" id="3_4sjsw"]
[ext_resource type="Resource" uid="uid://c3v8o4nubjakg" path="res://data/games/pacman.tres" id="4_wb1pw"]
[ext_resource type="Resource" uid="uid://d1gyyfaaclas8" path="res://data/cabinets/cabinet_02.tres" id="5_cy2se"]
[ext_resource type="Resource" uid="uid://cnfhiky5834pw" path="res://data/games/galaga.tres" id="6_r5ac2"]
[ext_resource type="Resource" uid="uid://d4ns05ptr4ybw" path="res://data/cabinets/cabinet_03.tres" id="7_4fvja"]
[ext_resource type="Resource" path="res://data/games/tempest.tres" id="8_uer0y"]
[ext_resource type="Resource" uid="uid://cwa2ord52vdda" path="res://data/cabinets/cabinet_04.tres" id="9_oms42"]
[ext_resource type="Resource" path="res://data/games/missile_command.tres" id="10_sqsy7"]
[ext_resource type="Script" uid="uid://d3pt6qa05kcnl" path="res://core/scenarios/scenario_definition.gd" id="11_2gwsy"]
[sub_resource type="Resource" id="Resource_p0bbs"]
script = ExtResource("1_40f70")
cabinet = ExtResource("2_nsmc3")
game = ExtResource("4_wb1pw")
metadata/_custom_type_script = "uid://ibujr0ervhhq"
[sub_resource type="Resource" id="Resource_46jx7"]
script = ExtResource("1_40f70")
cabinet = ExtResource("5_cy2se")
game = ExtResource("6_r5ac2")
metadata/_custom_type_script = "uid://ibujr0ervhhq"
[sub_resource type="Resource" id="Resource_vuaau"]
script = ExtResource("1_40f70")
cabinet = ExtResource("7_4fvja")
game = ExtResource("8_uer0y")
metadata/_custom_type_script = "uid://ibujr0ervhhq"
[sub_resource type="Resource" id="Resource_l1iuy"]
script = ExtResource("1_40f70")
cabinet = ExtResource("9_oms42")
game = ExtResource("10_sqsy7")
metadata/_custom_type_script = "uid://ibujr0ervhhq"
[resource]
script = ExtResource("11_2gwsy")
scenario_id = &"eg_glitch"
display_name = "Glitch: The Dark Machine"
assignments = Array[ExtResource("1_40f70")]([SubResource("Resource_p0bbs"), SubResource("Resource_46jx7"), SubResource("Resource_vuaau"), SubResource("Resource_l1iuy")])
metadata/_custom_type_script = "uid://d3pt6qa05kcnl"
@@ -0,0 +1,18 @@
[gd_resource type="Resource" script_class="ScenarioDefinition" format=3]
[ext_resource type="Script" path="res://core/scenarios/scenario_definition.gd" id="1"]
[ext_resource type="Script" path="res://core/scenarios/scenario_assignment.gd" id="2"]
[ext_resource type="Resource" path="res://data/cabinets/cabinet_01.tres" id="3"]
[ext_resource type="Resource" path="res://data/games/pacman.tres" id="4"]
[sub_resource type="Resource" id="Assignment"]
script = ExtResource("2")
cabinet = ExtResource("3")
game = ExtResource("4")
game_config = {"rfid_credit_device": "cab1_rfid1", "rfid_allowed_uids": [], "boards_to_win": 1, "score_to_win": 0}
[resource]
script = ExtResource("1")
scenario_id = &"pacman_rfid_credit_test"
display_name = "Cabinet 1: Pac-Man RFID credit"
assignments = Array[ExtResource("2")]([SubResource("Assignment")])
@@ -0,0 +1,47 @@
[gd_resource type="Resource" script_class="ScenarioDefinition" format=3 uid="uid://coylqrwbr26tb"]
[ext_resource type="Script" uid="uid://d3pt6qa05kcnl" path="res://core/scenarios/scenario_definition.gd" id="1"]
[ext_resource type="Script" uid="uid://ibujr0ervhhq" path="res://core/scenarios/scenario_assignment.gd" id="2"]
[ext_resource type="Resource" uid="uid://cl4j1vtv388pt" path="res://data/cabinets/cabinet_01.tres" id="3"]
[ext_resource type="Script" uid="uid://lixrugm1v2d2" path="res://core/scenarios/scenario_event_mapping.gd" id="3_my636"]
[ext_resource type="Resource" uid="uid://d1gyyfaaclas8" path="res://data/cabinets/cabinet_02.tres" id="4"]
[ext_resource type="Resource" uid="uid://d4ns05ptr4ybw" path="res://data/cabinets/cabinet_03.tres" id="5"]
[ext_resource type="Resource" uid="uid://c3v8o4nubjakg" path="res://data/games/pacman.tres" id="6"]
[ext_resource type="Resource" uid="uid://cnfhiky5834pw" path="res://data/games/galaga.tres" id="7"]
[ext_resource type="Resource" path="res://data/games/frogger.tres" id="8"]
[sub_resource type="Resource" id="First"]
script = ExtResource("2")
cabinet = ExtResource("3")
game = ExtResource("6")
game_config = {
"boards_to_win": 0,
"score_to_win": 0,
"test_auto_win_seconds": 5.0
}
[sub_resource type="Resource" id="Second"]
script = ExtResource("2")
cabinet = ExtResource("4")
game = ExtResource("7")
activate_after_win = &"cabinet_01"
game_config = {
"score_to_win": 500,
"stages_to_win": 0
}
[sub_resource type="Resource" id="Third"]
script = ExtResource("2")
cabinet = ExtResource("5")
game = ExtResource("8")
activate_after_win = &"cabinet_02"
game_config = {
"boards_to_win": 0,
"homes_to_win": 1
}
[resource]
script = ExtResource("1")
scenario_id = &"three_cabinet_objective_test"
display_name = "3-Cabinet Test: 5 seconds / 500 points / 1 frog"
assignments = Array[ExtResource("2")]([SubResource("First"), SubResource("Second"), SubResource("Third")])