Added Glitch Room Source code to Gitty
This commit is contained in:
commit
1ac9eb5644
505 files changed
+28504
No files matched your search
@@ -0,0 +1,8 @@
|
||||
@tool
|
||||
class_name CabinetPlacement
|
||||
extends Resource
|
||||
|
||||
|
||||
@export var cabinet_id: StringName = &""
|
||||
@export var position: Vector2 = Vector2.ZERO
|
||||
@export var rotation_degrees: float = 0.0
|
||||
@@ -0,0 +1 @@
|
||||
uid://cwblyetugbr4d
|
||||
@@ -0,0 +1,86 @@
|
||||
@tool
|
||||
class_name RoomDefinition
|
||||
extends Resource
|
||||
|
||||
|
||||
@export var room_id: StringName = &""
|
||||
@export var display_name: String = ""
|
||||
|
||||
@export var cabinet_placements: Array[CabinetPlacement] = []
|
||||
@export var devices: Array[RoomDeviceDefinition] = []
|
||||
@export var bindings: Array[RoomDeviceBinding] = []
|
||||
|
||||
@export_group("Geometry")
|
||||
@export var boundary_points: PackedVector2Array = PackedVector2Array()
|
||||
@export var walls: Array[RoomWallDefinition] = []
|
||||
|
||||
@export_group("Logic")
|
||||
|
||||
@export var logic_rules: Array[RoomLogicRule] = []
|
||||
|
||||
func get_device(
|
||||
device_id: StringName
|
||||
) -> RoomDeviceDefinition:
|
||||
|
||||
for device in devices:
|
||||
if device == null:
|
||||
continue
|
||||
|
||||
if device.device_id == device_id:
|
||||
return device
|
||||
|
||||
return null
|
||||
|
||||
|
||||
func get_cabinet_placement(
|
||||
cabinet_id: StringName
|
||||
) -> CabinetPlacement:
|
||||
|
||||
for placement in cabinet_placements:
|
||||
if placement == null:
|
||||
continue
|
||||
|
||||
if placement.cabinet_id == cabinet_id:
|
||||
return placement
|
||||
|
||||
return null
|
||||
|
||||
|
||||
func get_device_for_action(
|
||||
cabinet_id: StringName,
|
||||
action_id: StringName
|
||||
) -> RoomDeviceDefinition:
|
||||
|
||||
for binding in bindings:
|
||||
if binding == null:
|
||||
continue
|
||||
|
||||
if (
|
||||
binding.cabinet_id == cabinet_id
|
||||
and
|
||||
binding.hardware_action_id == action_id
|
||||
):
|
||||
return get_device(binding.device_id)
|
||||
|
||||
return null
|
||||
|
||||
func get_wall(
|
||||
wall_id: StringName
|
||||
) -> RoomWallDefinition:
|
||||
|
||||
for wall in walls:
|
||||
if wall == null:
|
||||
continue
|
||||
|
||||
if wall.wall_id == wall_id:
|
||||
return wall
|
||||
|
||||
return null
|
||||
|
||||
func has_wall(
|
||||
wall_id: StringName
|
||||
) -> bool:
|
||||
|
||||
return get_wall(
|
||||
wall_id
|
||||
) != null
|
||||
@@ -0,0 +1 @@
|
||||
uid://dgm2dkw5rar8i
|
||||
@@ -0,0 +1,15 @@
|
||||
@tool
|
||||
class_name RoomDeviceBinding
|
||||
extends Resource
|
||||
|
||||
|
||||
@export var cabinet_id: StringName = &""
|
||||
@export var hardware_action_id: StringName = &""
|
||||
|
||||
@export var device_id: StringName = &""
|
||||
|
||||
@export_group("Physical Cable Route")
|
||||
|
||||
@export var route_points: PackedVector2Array = (
|
||||
PackedVector2Array()
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
uid://r2rpbasss511
|
||||
@@ -0,0 +1,75 @@
|
||||
@tool
|
||||
class_name RoomDeviceDefinition
|
||||
extends Resource
|
||||
|
||||
|
||||
enum DeviceType {
|
||||
GENERIC,
|
||||
COIN_RELEASE,
|
||||
LIGHT,
|
||||
DOOR_LOCK,
|
||||
DRAWER_LOCK,
|
||||
BUZZER
|
||||
}
|
||||
|
||||
|
||||
enum Behavior {
|
||||
MOMENTARY,
|
||||
LATCHED
|
||||
}
|
||||
|
||||
|
||||
@export var device_id: StringName = &""
|
||||
@export var display_name: String = ""
|
||||
|
||||
@export var device_type: DeviceType = DeviceType.GENERIC
|
||||
@export var behavior: Behavior = Behavior.MOMENTARY
|
||||
|
||||
@export var initial_active: bool = false
|
||||
|
||||
|
||||
@export_group("Layout")
|
||||
@export var position: Vector2 = Vector2.ZERO
|
||||
|
||||
const FEET_TO_METERS: float = 0.3048
|
||||
const METERS_TO_FEET: float = 1.0 / FEET_TO_METERS
|
||||
|
||||
|
||||
#
|
||||
# Internal/storage representation.
|
||||
#
|
||||
@export_storage
|
||||
var physical_size_m: Vector2 = Vector2(
|
||||
0.25,
|
||||
0.25
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Designer-facing representation.
|
||||
#
|
||||
@export_group("Physical Dimensions")
|
||||
|
||||
@export_custom(
|
||||
PROPERTY_HINT_NONE,
|
||||
"suffix: ft"
|
||||
)
|
||||
var physical_size_ft: Vector2:
|
||||
get:
|
||||
return (
|
||||
physical_size_m
|
||||
* METERS_TO_FEET
|
||||
)
|
||||
set(value):
|
||||
physical_size_m = (
|
||||
value
|
||||
* FEET_TO_METERS
|
||||
)
|
||||
|
||||
|
||||
@export_group("Physical Appearance")
|
||||
|
||||
@export var editor_texture: Texture2D = null
|
||||
|
||||
@export_range(0.1, 4.0, 0.05)
|
||||
var editor_texture_scale: float = 1.0
|
||||
@@ -0,0 +1 @@
|
||||
uid://ejum18yr7xeo
|
||||
@@ -0,0 +1,420 @@
|
||||
class_name RoomEditSession
|
||||
extends RefCounted
|
||||
|
||||
|
||||
signal room_changed(room: RoomDefinition)
|
||||
signal dirty_changed(is_dirty: bool)
|
||||
signal saved
|
||||
signal reverted
|
||||
|
||||
|
||||
var source_room: RoomDefinition
|
||||
var working_room: RoomDefinition
|
||||
|
||||
var is_dirty: bool = false
|
||||
|
||||
var saved_state: Dictionary = {}
|
||||
|
||||
|
||||
func begin(room: RoomDefinition) -> bool:
|
||||
if room == null:
|
||||
push_error(
|
||||
"RoomEditSession cannot begin with a null room."
|
||||
)
|
||||
return false
|
||||
|
||||
source_room = room
|
||||
_create_working_copy()
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func mark_dirty() -> void:
|
||||
|
||||
if working_room == null:
|
||||
_set_dirty(
|
||||
false
|
||||
)
|
||||
return
|
||||
|
||||
var current_state := (
|
||||
_capture_room_state(
|
||||
working_room
|
||||
)
|
||||
)
|
||||
|
||||
_set_dirty(
|
||||
current_state != saved_state
|
||||
)
|
||||
|
||||
|
||||
func save() -> bool:
|
||||
if source_room == null:
|
||||
push_error(
|
||||
"RoomEditSession has no source room."
|
||||
)
|
||||
return false
|
||||
|
||||
if working_room == null:
|
||||
push_error(
|
||||
"RoomEditSession has no working room."
|
||||
)
|
||||
return false
|
||||
|
||||
_apply_working_copy_to_source()
|
||||
|
||||
var path := source_room.resource_path
|
||||
|
||||
if path.is_empty():
|
||||
push_error(
|
||||
"Source RoomDefinition has no resource path."
|
||||
)
|
||||
return false
|
||||
|
||||
var error := ResourceSaver.save(
|
||||
source_room,
|
||||
path
|
||||
)
|
||||
|
||||
if error != OK:
|
||||
push_error(
|
||||
"Failed to save RoomDefinition. Error: %s"
|
||||
% error
|
||||
)
|
||||
return false
|
||||
|
||||
print(
|
||||
"[ROOM EDITOR] Saved room to '%s'."
|
||||
% path
|
||||
)
|
||||
|
||||
saved_state = (
|
||||
_capture_room_state(
|
||||
working_room
|
||||
)
|
||||
)
|
||||
|
||||
_set_dirty(
|
||||
false
|
||||
)
|
||||
|
||||
saved.emit()
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func revert() -> void:
|
||||
|
||||
if source_room == null:
|
||||
return
|
||||
|
||||
_create_working_copy()
|
||||
|
||||
reverted.emit()
|
||||
|
||||
print(
|
||||
"[ROOM EDITOR] Reverted unsaved changes."
|
||||
)
|
||||
|
||||
func reload_from_disk() -> bool:
|
||||
|
||||
if source_room == null:
|
||||
return false
|
||||
|
||||
var path := (
|
||||
source_room.resource_path
|
||||
)
|
||||
|
||||
if path.is_empty():
|
||||
push_error(
|
||||
"Source RoomDefinition has no resource path."
|
||||
)
|
||||
return false
|
||||
|
||||
var reloaded := (
|
||||
ResourceLoader.load(
|
||||
path,
|
||||
"",
|
||||
ResourceLoader.CACHE_MODE_REPLACE
|
||||
)
|
||||
as RoomDefinition
|
||||
)
|
||||
|
||||
if reloaded == null:
|
||||
push_error(
|
||||
"Failed to reload RoomDefinition from '%s'."
|
||||
% path
|
||||
)
|
||||
return false
|
||||
|
||||
source_room = reloaded
|
||||
|
||||
_create_working_copy()
|
||||
|
||||
print(
|
||||
"[ROOM EDITOR] Reloaded room from disk: '%s'."
|
||||
% path
|
||||
)
|
||||
|
||||
return true
|
||||
|
||||
func _create_working_copy() -> void:
|
||||
|
||||
working_room = (
|
||||
_duplicate_room(
|
||||
source_room
|
||||
)
|
||||
)
|
||||
|
||||
saved_state = (
|
||||
_capture_room_state(
|
||||
working_room
|
||||
)
|
||||
)
|
||||
|
||||
_set_dirty(
|
||||
false
|
||||
)
|
||||
|
||||
room_changed.emit(
|
||||
working_room
|
||||
)
|
||||
|
||||
func _apply_working_copy_to_source() -> void:
|
||||
|
||||
for working_placement in working_room.cabinet_placements:
|
||||
if working_placement == null:
|
||||
continue
|
||||
|
||||
var source_placement := (
|
||||
source_room.get_cabinet_placement(
|
||||
working_placement.cabinet_id
|
||||
)
|
||||
)
|
||||
|
||||
if source_placement == null:
|
||||
continue
|
||||
|
||||
source_placement.position = (
|
||||
working_placement.position
|
||||
)
|
||||
|
||||
source_placement.rotation_degrees = (
|
||||
working_placement.rotation_degrees
|
||||
)
|
||||
|
||||
for working_device in working_room.devices:
|
||||
if working_device == null:
|
||||
continue
|
||||
|
||||
var source_device := (
|
||||
source_room.get_device(
|
||||
working_device.device_id
|
||||
)
|
||||
)
|
||||
|
||||
if source_device == null:
|
||||
continue
|
||||
|
||||
source_device.position = (
|
||||
working_device.position
|
||||
)
|
||||
|
||||
for working_binding in working_room.bindings:
|
||||
|
||||
if working_binding == null:
|
||||
continue
|
||||
|
||||
var source_binding: RoomDeviceBinding = null
|
||||
|
||||
for candidate in source_room.bindings:
|
||||
|
||||
if candidate == null:
|
||||
continue
|
||||
|
||||
if (
|
||||
candidate.cabinet_id
|
||||
== working_binding.cabinet_id
|
||||
and candidate.hardware_action_id
|
||||
== working_binding.hardware_action_id
|
||||
and candidate.device_id
|
||||
== working_binding.device_id
|
||||
):
|
||||
source_binding = candidate
|
||||
break
|
||||
|
||||
if source_binding == null:
|
||||
continue
|
||||
|
||||
source_binding.route_points = (
|
||||
working_binding.route_points.duplicate()
|
||||
)
|
||||
|
||||
#
|
||||
# Copy authored room geometry.
|
||||
#
|
||||
source_room.boundary_points = (
|
||||
working_room.boundary_points.duplicate()
|
||||
)
|
||||
|
||||
source_room.walls = _duplicate_walls(
|
||||
working_room.walls
|
||||
)
|
||||
|
||||
func _duplicate_room(
|
||||
source: RoomDefinition
|
||||
) -> RoomDefinition:
|
||||
|
||||
var copy := (
|
||||
source.duplicate(true)
|
||||
as RoomDefinition
|
||||
)
|
||||
|
||||
if copy == null:
|
||||
return null
|
||||
|
||||
#
|
||||
# Explicitly duplicate authored geometry so
|
||||
# wall Resources are never shared with source_room.
|
||||
#
|
||||
copy.boundary_points = (
|
||||
source.boundary_points.duplicate()
|
||||
)
|
||||
|
||||
copy.walls = _duplicate_walls(
|
||||
source.walls
|
||||
)
|
||||
|
||||
return copy
|
||||
|
||||
|
||||
func _duplicate_walls(
|
||||
source: Array[RoomWallDefinition]
|
||||
) -> Array[RoomWallDefinition]:
|
||||
|
||||
var result: Array[RoomWallDefinition] = []
|
||||
|
||||
for wall in source:
|
||||
if wall == null:
|
||||
continue
|
||||
|
||||
var copy := (
|
||||
wall.duplicate(true)
|
||||
as RoomWallDefinition
|
||||
)
|
||||
|
||||
if copy != null:
|
||||
result.append(
|
||||
copy
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
func _capture_room_state(
|
||||
room: RoomDefinition
|
||||
) -> Dictionary:
|
||||
|
||||
if room == null:
|
||||
return {}
|
||||
|
||||
var state := {
|
||||
"room_id": room.room_id,
|
||||
"display_name": room.display_name,
|
||||
"boundary_points": room.boundary_points.duplicate(),
|
||||
"cabinet_placements": [],
|
||||
"devices": [],
|
||||
"bindings": [],
|
||||
"walls": [],
|
||||
}
|
||||
|
||||
for placement in room.cabinet_placements:
|
||||
|
||||
if placement == null:
|
||||
state["cabinet_placements"].append(
|
||||
null
|
||||
)
|
||||
continue
|
||||
|
||||
state["cabinet_placements"].append(
|
||||
{
|
||||
"cabinet_id": placement.cabinet_id,
|
||||
"position": placement.position,
|
||||
"rotation_degrees": (
|
||||
placement.rotation_degrees
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
for device in room.devices:
|
||||
|
||||
if device == null:
|
||||
state["devices"].append(
|
||||
null
|
||||
)
|
||||
continue
|
||||
|
||||
state["devices"].append(
|
||||
{
|
||||
"device_id": device.device_id,
|
||||
"display_name": device.display_name,
|
||||
"device_type": device.device_type,
|
||||
"behavior": device.behavior,
|
||||
"initial_active": (
|
||||
device.initial_active
|
||||
),
|
||||
"position": device.position,
|
||||
}
|
||||
)
|
||||
|
||||
for binding in room.bindings:
|
||||
|
||||
if binding == null:
|
||||
state["bindings"].append(
|
||||
null
|
||||
)
|
||||
continue
|
||||
|
||||
state["bindings"].append(
|
||||
{
|
||||
"cabinet_id": binding.cabinet_id,
|
||||
"hardware_action_id": (
|
||||
binding.hardware_action_id
|
||||
),
|
||||
"device_id": binding.device_id,
|
||||
"route_points": (
|
||||
binding.route_points.duplicate()
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
for wall in room.walls:
|
||||
|
||||
if wall == null:
|
||||
state["walls"].append(
|
||||
null
|
||||
)
|
||||
continue
|
||||
|
||||
state["walls"].append(
|
||||
{
|
||||
"wall_id": wall.wall_id,
|
||||
"start": wall.start,
|
||||
"end": wall.end,
|
||||
"thickness": wall.thickness,
|
||||
}
|
||||
)
|
||||
|
||||
return state
|
||||
|
||||
func _set_dirty(
|
||||
value: bool
|
||||
) -> void:
|
||||
|
||||
if is_dirty == value:
|
||||
return
|
||||
|
||||
is_dirty = value
|
||||
|
||||
dirty_changed.emit(
|
||||
is_dirty
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
uid://w0en0xus0g5j
|
||||
@@ -0,0 +1,312 @@
|
||||
@tool
|
||||
class_name RoomSimulator
|
||||
extends Node
|
||||
|
||||
|
||||
signal device_state_changed(
|
||||
device_id: StringName,
|
||||
active: bool
|
||||
)
|
||||
|
||||
signal binding_activated(
|
||||
cabinet_id: StringName,
|
||||
action_id: StringName,
|
||||
device_id: StringName
|
||||
)
|
||||
|
||||
signal binding_deactivated(
|
||||
cabinet_id: StringName,
|
||||
action_id: StringName,
|
||||
device_id: StringName
|
||||
)
|
||||
|
||||
signal path_activated(
|
||||
path_id: StringName,
|
||||
cabinet_id: StringName,
|
||||
event_id: StringName,
|
||||
action_id: StringName,
|
||||
device_id: StringName
|
||||
)
|
||||
|
||||
signal path_deactivated(
|
||||
path_id: StringName,
|
||||
cabinet_id: StringName,
|
||||
event_id: StringName,
|
||||
action_id: StringName,
|
||||
device_id: StringName
|
||||
)
|
||||
|
||||
|
||||
var room: RoomDefinition
|
||||
var device_states: Dictionary = {}
|
||||
|
||||
|
||||
func configure(
|
||||
room_definition: RoomDefinition
|
||||
) -> void:
|
||||
|
||||
room = room_definition
|
||||
device_states.clear()
|
||||
|
||||
if room == null:
|
||||
push_error(
|
||||
"RoomSimulator received a null RoomDefinition."
|
||||
)
|
||||
return
|
||||
|
||||
for device in room.devices:
|
||||
if device == null:
|
||||
continue
|
||||
|
||||
device_states[
|
||||
device.device_id
|
||||
] = device.initial_active
|
||||
|
||||
if not Engine.is_editor_hint():
|
||||
_connect_hardware_manager()
|
||||
|
||||
print("")
|
||||
print("======= ROOM SIMULATOR =======")
|
||||
print("Room: ", room.display_name)
|
||||
print("Devices: ", room.devices.size())
|
||||
print("==============================")
|
||||
print("")
|
||||
|
||||
|
||||
func _connect_hardware_manager() -> void:
|
||||
|
||||
if not HardwareManager.action_activated.is_connected(
|
||||
_on_hardware_action_activated
|
||||
):
|
||||
HardwareManager.action_activated.connect(
|
||||
_on_hardware_action_activated
|
||||
)
|
||||
|
||||
if not HardwareManager.action_deactivated.is_connected(
|
||||
_on_hardware_action_deactivated
|
||||
):
|
||||
HardwareManager.action_deactivated.connect(
|
||||
_on_hardware_action_deactivated
|
||||
)
|
||||
|
||||
|
||||
func reset() -> void:
|
||||
|
||||
if room == null:
|
||||
return
|
||||
|
||||
for device in room.devices:
|
||||
if device == null:
|
||||
continue
|
||||
|
||||
_set_device_state(
|
||||
device.device_id,
|
||||
device.initial_active
|
||||
)
|
||||
|
||||
|
||||
func get_device_state(
|
||||
device_id: StringName
|
||||
) -> bool:
|
||||
|
||||
return device_states.get(
|
||||
device_id,
|
||||
false
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Runtime HardwareManager entry points
|
||||
#
|
||||
func _on_hardware_action_activated(
|
||||
cabinet_id: StringName,
|
||||
action_id: StringName,
|
||||
context: Dictionary
|
||||
) -> void:
|
||||
|
||||
_process_action_activated(
|
||||
cabinet_id,
|
||||
action_id,
|
||||
context
|
||||
)
|
||||
|
||||
|
||||
func _on_hardware_action_deactivated(
|
||||
cabinet_id: StringName,
|
||||
action_id: StringName,
|
||||
context: Dictionary
|
||||
) -> void:
|
||||
|
||||
_process_action_deactivated(
|
||||
cabinet_id,
|
||||
action_id,
|
||||
context
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Editor simulation entry points
|
||||
#
|
||||
func simulate_action_activated(
|
||||
cabinet_id: StringName,
|
||||
action_id: StringName,
|
||||
context: Dictionary = {}
|
||||
) -> void:
|
||||
|
||||
_process_action_activated(
|
||||
cabinet_id,
|
||||
action_id,
|
||||
context
|
||||
)
|
||||
|
||||
|
||||
func simulate_action_deactivated(
|
||||
cabinet_id: StringName,
|
||||
action_id: StringName,
|
||||
context: Dictionary = {}
|
||||
) -> void:
|
||||
|
||||
_process_action_deactivated(
|
||||
cabinet_id,
|
||||
action_id,
|
||||
context
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Shared processing
|
||||
#
|
||||
func _process_action_activated(
|
||||
cabinet_id: StringName,
|
||||
action_id: StringName,
|
||||
context: Dictionary
|
||||
) -> void:
|
||||
|
||||
if room == null:
|
||||
return
|
||||
|
||||
var device := room.get_device_for_action(
|
||||
cabinet_id,
|
||||
action_id
|
||||
)
|
||||
|
||||
if device == null:
|
||||
print(
|
||||
"[SIMULATION] No room device bound to %s:%s"
|
||||
% [
|
||||
cabinet_id,
|
||||
action_id
|
||||
]
|
||||
)
|
||||
return
|
||||
|
||||
var event_id := StringName(
|
||||
context.get(
|
||||
"game_event",
|
||||
"unknown_event"
|
||||
)
|
||||
)
|
||||
|
||||
var path_id := LogicPathId.make(
|
||||
cabinet_id,
|
||||
event_id,
|
||||
action_id,
|
||||
device.device_id
|
||||
)
|
||||
|
||||
path_activated.emit(
|
||||
path_id,
|
||||
cabinet_id,
|
||||
event_id,
|
||||
action_id,
|
||||
device.device_id
|
||||
)
|
||||
|
||||
binding_activated.emit(
|
||||
cabinet_id,
|
||||
action_id,
|
||||
device.device_id
|
||||
)
|
||||
|
||||
_set_device_state(
|
||||
device.device_id,
|
||||
true
|
||||
)
|
||||
|
||||
|
||||
func _process_action_deactivated(
|
||||
cabinet_id: StringName,
|
||||
action_id: StringName,
|
||||
context: Dictionary
|
||||
) -> void:
|
||||
|
||||
if room == null:
|
||||
return
|
||||
|
||||
var device := room.get_device_for_action(
|
||||
cabinet_id,
|
||||
action_id
|
||||
)
|
||||
|
||||
if device == null:
|
||||
return
|
||||
|
||||
var event_id := StringName(
|
||||
context.get(
|
||||
"game_event",
|
||||
"unknown_event"
|
||||
)
|
||||
)
|
||||
|
||||
var path_id := LogicPathId.make(
|
||||
cabinet_id,
|
||||
event_id,
|
||||
action_id,
|
||||
device.device_id
|
||||
)
|
||||
|
||||
path_deactivated.emit(
|
||||
path_id,
|
||||
cabinet_id,
|
||||
event_id,
|
||||
action_id,
|
||||
device.device_id
|
||||
)
|
||||
|
||||
binding_deactivated.emit(
|
||||
cabinet_id,
|
||||
action_id,
|
||||
device.device_id
|
||||
)
|
||||
|
||||
if (
|
||||
device.behavior
|
||||
== RoomDeviceDefinition.Behavior.MOMENTARY
|
||||
):
|
||||
_set_device_state(
|
||||
device.device_id,
|
||||
false
|
||||
)
|
||||
|
||||
|
||||
func _set_device_state(
|
||||
device_id: StringName,
|
||||
active: bool
|
||||
) -> void:
|
||||
|
||||
device_states[
|
||||
device_id
|
||||
] = active
|
||||
|
||||
print(
|
||||
"[SIMULATION] Device '%s' -> %s"
|
||||
% [
|
||||
device_id,
|
||||
"ACTIVE" if active else "INACTIVE"
|
||||
]
|
||||
)
|
||||
|
||||
device_state_changed.emit(
|
||||
device_id,
|
||||
active
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
uid://bfb7sad2mjnlf
|
||||
@@ -0,0 +1,102 @@
|
||||
class_name SimulatedHardwareBackend
|
||||
extends RefCounted
|
||||
|
||||
|
||||
signal pin_state_changed(
|
||||
cabinet_id: StringName,
|
||||
gpio_pin: int,
|
||||
active: bool,
|
||||
action_id: StringName,
|
||||
context: Dictionary
|
||||
)
|
||||
|
||||
signal trace_entry_created(
|
||||
entry: Dictionary
|
||||
)
|
||||
|
||||
|
||||
var pin_states: Dictionary = {}
|
||||
|
||||
|
||||
func reset() -> void:
|
||||
|
||||
pin_states.clear()
|
||||
|
||||
|
||||
func activate_action(
|
||||
cabinet_id: StringName,
|
||||
action: HardwareAction,
|
||||
context: Dictionary
|
||||
) -> void:
|
||||
|
||||
if action == null:
|
||||
return
|
||||
|
||||
var gpio_active := action.active_high
|
||||
|
||||
_set_pin_state(
|
||||
cabinet_id,
|
||||
action,
|
||||
gpio_active,
|
||||
true,
|
||||
context
|
||||
)
|
||||
|
||||
|
||||
func deactivate_action(
|
||||
cabinet_id: StringName,
|
||||
action: HardwareAction,
|
||||
context: Dictionary
|
||||
) -> void:
|
||||
|
||||
if action == null:
|
||||
return
|
||||
|
||||
var gpio_active := not action.active_high
|
||||
|
||||
_set_pin_state(
|
||||
cabinet_id,
|
||||
action,
|
||||
gpio_active,
|
||||
false,
|
||||
context
|
||||
)
|
||||
|
||||
|
||||
func _set_pin_state(
|
||||
cabinet_id: StringName,
|
||||
action: HardwareAction,
|
||||
electrical_state: bool,
|
||||
logical_active: bool,
|
||||
context: Dictionary
|
||||
) -> void:
|
||||
|
||||
var key := "%s::%d" % [
|
||||
cabinet_id,
|
||||
action.gpio_pin
|
||||
]
|
||||
|
||||
pin_states[key] = electrical_state
|
||||
|
||||
var entry := {
|
||||
"type": &"gpio",
|
||||
"cabinet_id": cabinet_id,
|
||||
"action_id": action.action_id,
|
||||
"gpio_pin": action.gpio_pin,
|
||||
"electrical_state": electrical_state,
|
||||
"logical_active": logical_active,
|
||||
"active_high": action.active_high,
|
||||
"context": context.duplicate(),
|
||||
}
|
||||
|
||||
trace_entry_created.emit(
|
||||
entry
|
||||
)
|
||||
|
||||
pin_state_changed.emit(
|
||||
cabinet_id,
|
||||
action.gpio_pin,
|
||||
logical_active,
|
||||
action.action_id,
|
||||
context
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
uid://b3xyoxcebkhoc
|
||||
@@ -0,0 +1,42 @@
|
||||
@tool
|
||||
class_name TestSequence
|
||||
extends Resource
|
||||
|
||||
|
||||
@export var sequence_id: StringName = &""
|
||||
@export var display_name: String = ""
|
||||
@export_group("Compatibility")
|
||||
@export var scenario_id: StringName = &""
|
||||
|
||||
@export_multiline
|
||||
var description: String = ""
|
||||
|
||||
@export var steps: Array[TestSequenceStep] = []
|
||||
|
||||
|
||||
func get_sorted_steps() -> Array[TestSequenceStep]:
|
||||
|
||||
var result: Array[TestSequenceStep] = []
|
||||
|
||||
for step in steps:
|
||||
|
||||
if step == null:
|
||||
continue
|
||||
|
||||
result.append(
|
||||
step
|
||||
)
|
||||
|
||||
result.sort_custom(
|
||||
func(
|
||||
a: TestSequenceStep,
|
||||
b: TestSequenceStep
|
||||
) -> bool:
|
||||
|
||||
return (
|
||||
a.time_offset_seconds
|
||||
< b.time_offset_seconds
|
||||
)
|
||||
)
|
||||
|
||||
return result
|
||||
@@ -0,0 +1 @@
|
||||
uid://clbm4alwyibrd
|
||||
@@ -0,0 +1,13 @@
|
||||
@tool
|
||||
class_name TestSequenceStep
|
||||
extends Resource
|
||||
|
||||
|
||||
@export_range(0.0, 36000.0, 0.1)
|
||||
var time_offset_seconds: float = 0.0
|
||||
|
||||
@export var source_id: StringName = &""
|
||||
@export var event_id: StringName = &""
|
||||
|
||||
@export_multiline
|
||||
var note: String = ""
|
||||
@@ -0,0 +1 @@
|
||||
uid://c5022gsswr487
|
||||
Reference in new issue
Block a user