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
188 lines
3.1 KiB
GDScript
188 lines
3.1 KiB
GDScript
@tool
|
|
extends EditorPlugin
|
|
|
|
|
|
const WORKSPACE_SCENE := preload(
|
|
"res://editor/workspace/EscapeRoomWorkspace.tscn"
|
|
)
|
|
|
|
const DATABASE_SETTING := (
|
|
"arcade_escape/project_database"
|
|
)
|
|
|
|
const ROOM_SETTING := (
|
|
"arcade_escape/default_room"
|
|
)
|
|
|
|
|
|
var pcb_inspector: EditorInspectorPlugin
|
|
var workspace: EscapeRoomWorkspace
|
|
|
|
|
|
func _enter_tree() -> void:
|
|
pcb_inspector = preload("res://addons/escape_room/pcb_inspector.gd").new()
|
|
add_inspector_plugin(pcb_inspector)
|
|
_ensure_project_settings()
|
|
_create_workspace()
|
|
|
|
|
|
func _exit_tree() -> void:
|
|
remove_inspector_plugin(pcb_inspector)
|
|
pcb_inspector = null
|
|
_destroy_workspace()
|
|
|
|
|
|
func _has_main_screen() -> bool:
|
|
return true
|
|
|
|
|
|
func _make_visible(visible: bool) -> void:
|
|
if workspace != null:
|
|
workspace.visible = visible
|
|
|
|
|
|
func _get_plugin_name() -> String:
|
|
return "Escape Room"
|
|
|
|
|
|
func _get_plugin_icon() -> Texture2D:
|
|
return EditorInterface.get_editor_theme().get_icon(
|
|
"Node2D",
|
|
"EditorIcons"
|
|
)
|
|
|
|
|
|
func _create_workspace() -> void:
|
|
|
|
if workspace != null:
|
|
return
|
|
|
|
var database := _load_project_database()
|
|
var room := _load_default_room()
|
|
|
|
if database == null:
|
|
return
|
|
|
|
if room == null:
|
|
return
|
|
|
|
workspace = WORKSPACE_SCENE.instantiate()
|
|
|
|
workspace.set_undo_redo_manager(
|
|
get_undo_redo()
|
|
)
|
|
|
|
EditorInterface.get_editor_main_screen().add_child(
|
|
workspace
|
|
)
|
|
|
|
workspace.set_anchors_and_offsets_preset(
|
|
Control.PRESET_FULL_RECT
|
|
)
|
|
|
|
if not workspace.configure(
|
|
database,
|
|
room
|
|
):
|
|
push_error(
|
|
"Arcade Escape editor workspace failed to configure."
|
|
)
|
|
|
|
_make_visible(false)
|
|
|
|
|
|
func _destroy_workspace() -> void:
|
|
if workspace == null:
|
|
return
|
|
|
|
if is_instance_valid(workspace):
|
|
workspace.queue_free()
|
|
|
|
workspace = null
|
|
|
|
func _ensure_project_settings() -> void:
|
|
|
|
if not ProjectSettings.has_setting(
|
|
DATABASE_SETTING
|
|
):
|
|
ProjectSettings.set_setting(
|
|
DATABASE_SETTING,
|
|
"res://data/project_database.tres"
|
|
)
|
|
|
|
ProjectSettings.set_initial_value(
|
|
DATABASE_SETTING,
|
|
"res://data/project_database.tres"
|
|
)
|
|
|
|
if not ProjectSettings.has_setting(
|
|
ROOM_SETTING
|
|
):
|
|
ProjectSettings.set_setting(
|
|
ROOM_SETTING,
|
|
"res://data/rooms/arcade_room.tres"
|
|
)
|
|
|
|
ProjectSettings.set_initial_value(
|
|
ROOM_SETTING,
|
|
"res://data/rooms/arcade_room.tres"
|
|
)
|
|
|
|
ProjectSettings.save()
|
|
|
|
func _load_project_database() -> ProjectDatabase:
|
|
|
|
var path := String(
|
|
ProjectSettings.get_setting(
|
|
DATABASE_SETTING,
|
|
""
|
|
)
|
|
)
|
|
|
|
if path.is_empty():
|
|
push_error(
|
|
"Arcade Escape project database path is empty."
|
|
)
|
|
return null
|
|
|
|
var resource := ResourceLoader.load(
|
|
path
|
|
)
|
|
|
|
if not resource is ProjectDatabase:
|
|
push_error(
|
|
"Arcade Escape expected ProjectDatabase at '%s'."
|
|
% path
|
|
)
|
|
return null
|
|
|
|
return resource as ProjectDatabase
|
|
|
|
func _load_default_room() -> RoomDefinition:
|
|
|
|
var path := String(
|
|
ProjectSettings.get_setting(
|
|
ROOM_SETTING,
|
|
""
|
|
)
|
|
)
|
|
|
|
if path.is_empty():
|
|
push_error(
|
|
"Arcade Escape default room path is empty."
|
|
)
|
|
return null
|
|
|
|
var resource := ResourceLoader.load(
|
|
path
|
|
)
|
|
|
|
if not resource is RoomDefinition:
|
|
push_error(
|
|
"Arcade Escape expected RoomDefinition at '%s'."
|
|
% path
|
|
)
|
|
return null
|
|
|
|
return resource as RoomDefinition
|