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,423 @@
|
||||
[gd_scene format=3 uid="uid://d0c4psurpl2f2"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://ca320x55f2h3y" path="res://ui/room_layout.gd" id="1_0vaos"]
|
||||
[ext_resource type="Script" uid="uid://jxob25ucisxl" path="res://editor/workspace/escape_room_workspace.gd" id="1_moiuv"]
|
||||
[ext_resource type="Script" uid="uid://bfb7sad2mjnlf" path="res://core/simulation/room_simulator.gd" id="1_ynivy"]
|
||||
[ext_resource type="PackedScene" uid="uid://c5c0mnwwuqruw" path="res://ui/RoomLayoutItem.tscn" id="2_ynivy"]
|
||||
[ext_resource type="ButtonGroup" uid="uid://cly57dx12c8dg" path="res://data/editor/buttonGroup.tres" id="3_fj88e"]
|
||||
[ext_resource type="Script" uid="uid://dm5remdyomnc4" path="res://ui/logic_graph.gd" id="3_moiuv"]
|
||||
[ext_resource type="Script" uid="uid://b0tn15y67fac4" path="res://editor/workspace/simulation_timeline.gd" id="7_prwl5"]
|
||||
|
||||
[node name="EscapeRoomWorkspace" type="Control" unique_id=1163239148]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
script = ExtResource("1_moiuv")
|
||||
|
||||
[node name="RoomSimulator" type="Node" parent="." unique_id=2142830911]
|
||||
script = ExtResource("1_ynivy")
|
||||
metadata/_custom_type_script = "uid://bfb7sad2mjnlf"
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=764379781]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="Toolbar" type="HBoxContainer" parent="VBoxContainer" unique_id=863837601]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ScenarioLabel" type="Label" parent="VBoxContainer/Toolbar" unique_id=1332916735]
|
||||
layout_mode = 2
|
||||
text = "SCENARIO"
|
||||
|
||||
[node name="ScenarioSelect" type="OptionButton" parent="VBoxContainer/Toolbar" unique_id=57947397]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ValidateButton" type="Button" parent="VBoxContainer/Toolbar" unique_id=1178727524]
|
||||
layout_mode = 2
|
||||
text = "VALIDATE"
|
||||
|
||||
[node name="Spacer" type="VSeparator" parent="VBoxContainer/Toolbar" unique_id=1649273947]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="VBoxContainer/Toolbar" unique_id=2058830606]
|
||||
layout_mode = 2
|
||||
text = "STATUS"
|
||||
|
||||
[node name="SimulationBar" type="HBoxContainer" parent="VBoxContainer" unique_id=359662494]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="TestLabel" type="Label" parent="VBoxContainer/SimulationBar" unique_id=103460454]
|
||||
layout_mode = 2
|
||||
text = "TEST:"
|
||||
|
||||
[node name="TestCabinetSelect" type="OptionButton" parent="VBoxContainer/SimulationBar" unique_id=1218863658]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="TestEventSelect" type="OptionButton" parent="VBoxContainer/SimulationBar" unique_id=700842260]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="TestEventButton" type="Button" parent="VBoxContainer/SimulationBar" unique_id=763809162]
|
||||
layout_mode = 2
|
||||
text = "FIRE EVENT"
|
||||
|
||||
[node name="MainViews" type="TabContainer" parent="VBoxContainer" unique_id=442177872]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
current_tab = 1
|
||||
|
||||
[node name="Physical" type="Control" parent="VBoxContainer/MainViews" unique_id=642902521]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
metadata/_tab_index = 0
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/MainViews/Physical" unique_id=53218428]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="PhysicalToolbar" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer" unique_id=1361233586]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="SelectButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=1918084356]
|
||||
layout_mode = 2
|
||||
toggle_mode = true
|
||||
button_pressed = true
|
||||
button_group = ExtResource("3_fj88e")
|
||||
text = "SELECT"
|
||||
|
||||
[node name="DrawWallButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=1782596667]
|
||||
layout_mode = 2
|
||||
toggle_mode = true
|
||||
button_group = ExtResource("3_fj88e")
|
||||
text = "DRAW WALL"
|
||||
|
||||
[node name="EditBoundaryButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=1099180096]
|
||||
layout_mode = 2
|
||||
toggle_mode = true
|
||||
button_group = ExtResource("3_fj88e")
|
||||
text = "EDIT BOUNDARY"
|
||||
|
||||
[node name="AddBoundaryPointButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=1392564272]
|
||||
layout_mode = 2
|
||||
toggle_mode = true
|
||||
button_group = ExtResource("3_fj88e")
|
||||
text = "ADD POINT"
|
||||
|
||||
[node name="DeleteBoundaryPointButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=121279084]
|
||||
layout_mode = 2
|
||||
toggle_mode = true
|
||||
button_group = ExtResource("3_fj88e")
|
||||
text = "DELETE POINT"
|
||||
|
||||
[node name="FocusRoomButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=1583370791]
|
||||
layout_mode = 2
|
||||
toggle_mode = true
|
||||
text = "FOCUS ON ROOM"
|
||||
|
||||
[node name="ResetViewButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=1229994678]
|
||||
layout_mode = 2
|
||||
toggle_mode = true
|
||||
text = "RESET VIEW"
|
||||
|
||||
[node name="ZoomLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=671655429]
|
||||
layout_mode = 2
|
||||
text = "100%"
|
||||
|
||||
[node name="LayoutWorkspace" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer" unique_id=1651349629]
|
||||
propagate_maximum_size = false
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="RoomLayoutPanel" type="PanelContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace" unique_id=1991145282]
|
||||
custom_minimum_size = Vector2(0, 300)
|
||||
clip_contents = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="RoomLayout" type="Control" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/RoomLayoutPanel" unique_id=1170586875]
|
||||
layout_mode = 2
|
||||
focus_mode = 2
|
||||
script = ExtResource("1_0vaos")
|
||||
item_scene = ExtResource("2_ynivy")
|
||||
grid_size_meters = 0.305
|
||||
|
||||
[node name="PropertyPanel" type="PanelContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace" unique_id=1004135858]
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
custom_maximum_size = Vector2(300, -1)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel" unique_id=2020502330]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer" unique_id=57561269]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="PropertiesTitle" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=201532758]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="SelectedLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1453764819]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1092920259]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="XContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1033218596]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="XLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/XContainer" unique_id=18757878]
|
||||
layout_mode = 2
|
||||
text = "X (ft)"
|
||||
|
||||
[node name="XSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/XContainer" unique_id=2096096703]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
min_value = -6562.0
|
||||
max_value = 16405.0
|
||||
step = 0.001
|
||||
allow_greater = true
|
||||
allow_lesser = true
|
||||
|
||||
[node name="YContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=42809798]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="YLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/YContainer" unique_id=1673769933]
|
||||
layout_mode = 2
|
||||
text = "Y (ft)"
|
||||
|
||||
[node name="YSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/YContainer" unique_id=1535738497]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
min_value = -6562.0
|
||||
max_value = 16405.0
|
||||
step = 0.001
|
||||
allow_greater = true
|
||||
allow_lesser = true
|
||||
|
||||
[node name="RotationContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=993197800]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="RotationLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/RotationContainer" unique_id=555802567]
|
||||
layout_mode = 2
|
||||
text = "ROTATE"
|
||||
|
||||
[node name="RotationSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/RotationContainer" unique_id=1837154818]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
min_value = -360.0
|
||||
max_value = 360.0
|
||||
editable = false
|
||||
|
||||
[node name="SnapCheckBox" type="CheckBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1856155383]
|
||||
layout_mode = 2
|
||||
button_pressed = true
|
||||
text = "Snap to Grid"
|
||||
|
||||
[node name="GridContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1969314828]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="GridLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/GridContainer" unique_id=1070729216]
|
||||
layout_mode = 2
|
||||
text = "Grid (ft)"
|
||||
|
||||
[node name="GridSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/GridContainer" unique_id=823428489]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
min_value = 0.05
|
||||
max_value = 7.0
|
||||
step = 0.001
|
||||
value = 1.001
|
||||
|
||||
[node name="HSeparator2" type="HSeparator" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=2075347966]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="DirtyLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=164864025]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="SaveButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=2059276515]
|
||||
layout_mode = 2
|
||||
text = "SAVE ROOM"
|
||||
|
||||
[node name="RevertButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1017042755]
|
||||
layout_mode = 2
|
||||
text = "REVERT"
|
||||
|
||||
[node name="ShowConnectionsCheckBox" type="CheckBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=112263641]
|
||||
layout_mode = 2
|
||||
button_pressed = true
|
||||
text = "Show Connections"
|
||||
|
||||
[node name="HSeparator3" type="HSeparator" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1552395963]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="WallStartXContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1767771179]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="WallStartXLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallStartXContainer" unique_id=1029352572]
|
||||
layout_mode = 2
|
||||
text = "Start X (ft)"
|
||||
|
||||
[node name="WallStartXSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallStartXContainer" unique_id=1517604292]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
min_value = -6562.0
|
||||
max_value = 16405.0
|
||||
step = 0.001
|
||||
allow_greater = true
|
||||
allow_lesser = true
|
||||
|
||||
[node name="WallStartYContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1191148572]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="WallStartYLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallStartYContainer" unique_id=2056551712]
|
||||
layout_mode = 2
|
||||
text = "Start Y (ft)"
|
||||
|
||||
[node name="WallStartYSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallStartYContainer" unique_id=1446663095]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
min_value = -6562.0
|
||||
max_value = 16405.0
|
||||
step = 0.001
|
||||
allow_greater = true
|
||||
allow_lesser = true
|
||||
|
||||
[node name="HSeparator4" type="HSeparator" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1250367093]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="WallEndXContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1087233909]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="WallEndXLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallEndXContainer" unique_id=1469094168]
|
||||
layout_mode = 2
|
||||
text = "End X (ft)"
|
||||
|
||||
[node name="WallEndXSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallEndXContainer" unique_id=401819232]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
min_value = -6562.0
|
||||
max_value = 16405.0
|
||||
step = 0.001
|
||||
allow_greater = true
|
||||
allow_lesser = true
|
||||
|
||||
[node name="WallEndYContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=575834449]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="WallEndYLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallEndYContainer" unique_id=87035740]
|
||||
layout_mode = 2
|
||||
text = "End Y (ft)"
|
||||
|
||||
[node name="WallEndYSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallEndYContainer" unique_id=1018331962]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
min_value = -6562.0
|
||||
max_value = 16405.0
|
||||
step = 0.001
|
||||
allow_greater = true
|
||||
allow_lesser = true
|
||||
|
||||
[node name="WallThicknessContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=75655223]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="WallThicknessLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallThicknessContainer" unique_id=167585585]
|
||||
layout_mode = 2
|
||||
text = "Thickness"
|
||||
|
||||
[node name="WallThicknessSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallThicknessContainer" unique_id=803776797]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
min_value = 0.01
|
||||
max_value = 4.0
|
||||
step = 0.01
|
||||
value = 0.09999999999999999
|
||||
suffix = " ft"
|
||||
|
||||
[node name="DeleteWallButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=933863750]
|
||||
layout_mode = 2
|
||||
text = "DELETE WALL"
|
||||
|
||||
[node name="Logic" type="Control" parent="VBoxContainer/MainViews" unique_id=323886775]
|
||||
layout_mode = 2
|
||||
metadata/_tab_index = 1
|
||||
|
||||
[node name="AutoArrangeButton" type="Button" parent="VBoxContainer/MainViews/Logic" unique_id=924050908]
|
||||
layout_mode = 0
|
||||
offset_left = 1786.0
|
||||
offset_top = -29.0
|
||||
offset_right = 1917.0
|
||||
offset_bottom = 2.0
|
||||
text = "AUTO ARRANGE"
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/MainViews/Logic" unique_id=1993927655]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="EditorBar" type="HBoxContainer" parent="VBoxContainer/MainViews/Logic/VBoxContainer" unique_id=723659829]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ScenarioDirtyLabel" type="Label" parent="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar" unique_id=1492077890]
|
||||
layout_mode = 2
|
||||
text = "SCENARIO SAVED"
|
||||
|
||||
[node name="VSeparator" type="VSeparator" parent="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar" unique_id=812436932]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ValidateScenarioButton" type="Button" parent="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar" unique_id=277208391]
|
||||
layout_mode = 2
|
||||
text = "VALIDATE"
|
||||
|
||||
[node name="SaveScenarioButton" type="Button" parent="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar" unique_id=100451844]
|
||||
layout_mode = 2
|
||||
text = "SAVE
|
||||
"
|
||||
|
||||
[node name="RevertScenarioButton" type="Button" parent="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar" unique_id=1682080798]
|
||||
layout_mode = 2
|
||||
text = "REVERT"
|
||||
|
||||
[node name="LogicGraph" type="GraphEdit" parent="VBoxContainer/MainViews/Logic/VBoxContainer" unique_id=628220896]
|
||||
propagate_maximum_size = true
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
theme_override_colors/activity = Color(0, 1, 0.278, 1)
|
||||
script = ExtResource("3_moiuv")
|
||||
|
||||
[node name="SimulationTimeline" type="VBoxContainer" parent="VBoxContainer" unique_id=759773235]
|
||||
custom_minimum_size = Vector2(0, 180)
|
||||
layout_mode = 2
|
||||
script = ExtResource("7_prwl5")
|
||||
|
||||
[connection signal="item_selected" from="VBoxContainer/Toolbar/ScenarioSelect" to="." method="_on_scenario_select_item_selected"]
|
||||
[connection signal="pressed" from="VBoxContainer/Toolbar/ValidateButton" to="." method="_on_validate_button_pressed"]
|
||||
[connection signal="item_selected" from="VBoxContainer/SimulationBar/TestCabinetSelect" to="." method="_on_test_cabinet_select_item_selected"]
|
||||
[connection signal="pressed" from="VBoxContainer/SimulationBar/TestEventButton" to="." method="_on_test_event_button_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar/SelectButton" to="." method="_on_select_tool_button_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar/DrawWallButton" to="." method="_on_draw_wall_button_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/SaveButton" to="." method="_on_save_room_button_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/RevertButton" to="." method="_on_revert_room_button_pressed"]
|
||||
[connection signal="toggled" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/ShowConnectionsCheckBox" to="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/RoomLayoutPanel/RoomLayout" method="_on_show_connections_check_box_toggled"]
|
||||
[connection signal="value_changed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallStartXContainer/WallStartXSpinBox" to="." method="_on_wall_start_x_spin_box_value_changed"]
|
||||
[connection signal="value_changed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallStartYContainer/WallStartYSpinBox" to="." method="_on_wall_start_y_spin_box_value_changed"]
|
||||
[connection signal="value_changed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallEndXContainer/WallEndXSpinBox" to="." method="_on_wall_end_x_spin_box_value_changed"]
|
||||
[connection signal="value_changed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallEndYContainer/WallEndYSpinBox" to="." method="_on_wall_end_y_spin_box_value_changed"]
|
||||
[connection signal="value_changed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallThicknessContainer/WallThicknessSpinBox" to="." method="_on_wall_thickness_spin_box_value_changed"]
|
||||
[connection signal="pressed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/DeleteWallButton" to="." method="_on_delete_wall_button_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar/ValidateScenarioButton" to="." method="_on_validate_scenario_button_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar/SaveScenarioButton" to="." method="_on_save_scenario_button_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar/RevertScenarioButton" to="." method="_on_revert_scenario_button_pressed"]
|
||||
@@ -0,0 +1,983 @@
|
||||
@tool
|
||||
class_name EditorSimulationDriver
|
||||
extends RefCounted
|
||||
|
||||
|
||||
signal action_activated(
|
||||
cabinet_id: StringName,
|
||||
action_id: StringName,
|
||||
context: Dictionary
|
||||
)
|
||||
|
||||
signal action_deactivated(
|
||||
cabinet_id: StringName,
|
||||
action_id: StringName,
|
||||
context: Dictionary
|
||||
)
|
||||
|
||||
signal device_state_changed(
|
||||
device_id: StringName,
|
||||
active: bool
|
||||
)
|
||||
|
||||
signal trace_entry_created(
|
||||
entry: Dictionary
|
||||
)
|
||||
|
||||
signal sequence_started(
|
||||
sequence: TestSequence
|
||||
)
|
||||
|
||||
signal sequence_finished(
|
||||
sequence: TestSequence
|
||||
)
|
||||
|
||||
signal sequence_stopped
|
||||
|
||||
var sequence_settling: bool = false
|
||||
var room: RoomDefinition
|
||||
var scenario: ScenarioDefinition
|
||||
var logic_engine: RoomLogicEngine
|
||||
var simulated_device_states: Dictionary = {}
|
||||
var hardware_backend: SimulatedHardwareBackend
|
||||
|
||||
var pending_hardware_deactivations: Array[Dictionary] = []
|
||||
|
||||
var paused: bool = false
|
||||
|
||||
var active_sequence: TestSequence = null
|
||||
|
||||
var sequence_start_time: float = 0.0
|
||||
|
||||
var pending_sequence_steps: Array[Dictionary] = []
|
||||
|
||||
var sequence_running: bool = false
|
||||
|
||||
func start_sequence(
|
||||
sequence: TestSequence
|
||||
) -> void:
|
||||
|
||||
if sequence == null:
|
||||
return
|
||||
|
||||
#
|
||||
# Starting a rehearsal means starting from
|
||||
# a clean simulated-room state.
|
||||
#
|
||||
reset_simulation()
|
||||
|
||||
active_sequence = sequence
|
||||
|
||||
sequence_start_time = (
|
||||
_get_simulation_time()
|
||||
)
|
||||
|
||||
pending_sequence_steps.clear()
|
||||
|
||||
for step in sequence.get_sorted_steps():
|
||||
|
||||
pending_sequence_steps.append(
|
||||
{
|
||||
"execute_at": (
|
||||
sequence_start_time
|
||||
+ step.time_offset_seconds
|
||||
),
|
||||
|
||||
"step": step,
|
||||
}
|
||||
)
|
||||
|
||||
sequence_running = true
|
||||
sequence_settling = false
|
||||
|
||||
trace_entry_created.emit(
|
||||
{
|
||||
"type": &"sequence",
|
||||
"time": _get_simulation_time(),
|
||||
"sequence_id": sequence.sequence_id,
|
||||
"display_name": sequence.display_name,
|
||||
"state": &"started",
|
||||
}
|
||||
)
|
||||
|
||||
sequence_started.emit(
|
||||
sequence
|
||||
)
|
||||
|
||||
#
|
||||
# Execute all steps authored at 0.0 immediately.
|
||||
#
|
||||
_process_pending_sequence_steps()
|
||||
|
||||
|
||||
func advance(
|
||||
delta_seconds: float
|
||||
) -> void:
|
||||
|
||||
if paused:
|
||||
return
|
||||
|
||||
_advance_internal(
|
||||
delta_seconds
|
||||
)
|
||||
|
||||
func configure(
|
||||
room_definition: RoomDefinition,
|
||||
scenario_definition: ScenarioDefinition
|
||||
) -> void:
|
||||
|
||||
room = room_definition
|
||||
scenario = scenario_definition
|
||||
|
||||
pending_hardware_deactivations.clear()
|
||||
simulated_device_states.clear()
|
||||
|
||||
logic_engine = RoomLogicEngine.new()
|
||||
|
||||
logic_engine.configure(
|
||||
room_definition
|
||||
)
|
||||
|
||||
logic_engine.action_requested.connect(
|
||||
_on_logic_action_requested
|
||||
)
|
||||
|
||||
logic_engine.trace_entry_created.connect(
|
||||
_on_logic_trace_entry_created
|
||||
)
|
||||
|
||||
hardware_backend = SimulatedHardwareBackend.new()
|
||||
|
||||
hardware_backend.pin_state_changed.connect(
|
||||
_on_simulated_pin_state_changed
|
||||
)
|
||||
|
||||
hardware_backend.trace_entry_created.connect(
|
||||
_on_hardware_trace_entry_created
|
||||
)
|
||||
|
||||
func simulate_game_event(
|
||||
cabinet_id: StringName,
|
||||
event_id: StringName
|
||||
) -> void:
|
||||
|
||||
if scenario == null:
|
||||
push_error(
|
||||
"EditorSimulationDriver has no scenario."
|
||||
)
|
||||
return
|
||||
|
||||
var assignment := (
|
||||
scenario.get_assignment_for_cabinet(
|
||||
cabinet_id
|
||||
)
|
||||
)
|
||||
|
||||
if assignment == null:
|
||||
push_error(
|
||||
"No scenario assignment exists for cabinet '%s'."
|
||||
% cabinet_id
|
||||
)
|
||||
return
|
||||
|
||||
#
|
||||
# Feed the event into the room-level logic engine.
|
||||
#
|
||||
emit_room_event(
|
||||
cabinet_id,
|
||||
event_id
|
||||
)
|
||||
|
||||
#
|
||||
# Preserve the existing scenario mapping:
|
||||
#
|
||||
# game event
|
||||
# -> cabinet hardware action
|
||||
#
|
||||
var actions := (
|
||||
assignment.get_actions_for_event(
|
||||
event_id
|
||||
)
|
||||
)
|
||||
|
||||
for action_id in actions:
|
||||
|
||||
_activate_action(
|
||||
cabinet_id,
|
||||
action_id,
|
||||
{
|
||||
"game_event": event_id
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
func _activate_action(
|
||||
cabinet_id: StringName,
|
||||
action_id: StringName,
|
||||
context: Dictionary
|
||||
) -> void:
|
||||
|
||||
if room == null:
|
||||
return
|
||||
|
||||
var assignment := (
|
||||
scenario.get_assignment_for_cabinet(
|
||||
cabinet_id
|
||||
)
|
||||
)
|
||||
|
||||
if assignment == null:
|
||||
return
|
||||
|
||||
if assignment.cabinet == null:
|
||||
return
|
||||
|
||||
if assignment.cabinet.hardware_config == null:
|
||||
return
|
||||
|
||||
var action := (
|
||||
assignment.cabinet.hardware_config.get_action(
|
||||
action_id
|
||||
)
|
||||
)
|
||||
|
||||
if action == null:
|
||||
push_error(
|
||||
"Editor simulation could not find hardware action '%s' on cabinet '%s'."
|
||||
% [
|
||||
action_id,
|
||||
cabinet_id
|
||||
]
|
||||
)
|
||||
return
|
||||
|
||||
action_activated.emit(
|
||||
cabinet_id,
|
||||
action_id,
|
||||
context
|
||||
)
|
||||
|
||||
hardware_backend.activate_action(
|
||||
cabinet_id,
|
||||
action,
|
||||
context
|
||||
)
|
||||
|
||||
match action.action_type:
|
||||
HardwareAction.ActionType.PULSE_OUTPUT:
|
||||
_schedule_deactivation(
|
||||
cabinet_id,
|
||||
action_id,
|
||||
context,
|
||||
action.pulse_duration_ms
|
||||
)
|
||||
|
||||
HardwareAction.ActionType.DIGITAL_OUTPUT:
|
||||
#
|
||||
# For now, treat a digital output as latched.
|
||||
# We'll add explicit ON/OFF editing later.
|
||||
#
|
||||
pass
|
||||
|
||||
|
||||
func _schedule_deactivation(
|
||||
cabinet_id: StringName,
|
||||
action_id: StringName,
|
||||
context: Dictionary,
|
||||
duration_ms: int
|
||||
) -> void:
|
||||
|
||||
var duration_seconds := (
|
||||
float(duration_ms)
|
||||
/ 1000.0
|
||||
)
|
||||
|
||||
pending_hardware_deactivations.append(
|
||||
{
|
||||
"execute_at": (
|
||||
_get_simulation_time()
|
||||
+ duration_seconds
|
||||
),
|
||||
|
||||
"cabinet_id": cabinet_id,
|
||||
"action_id": action_id,
|
||||
"context": context.duplicate(),
|
||||
}
|
||||
)
|
||||
|
||||
func _get_simulation_time() -> float:
|
||||
|
||||
if logic_engine == null:
|
||||
return 0.0
|
||||
|
||||
return logic_engine.get_simulation_time()
|
||||
|
||||
func emit_room_event(
|
||||
source_id: StringName,
|
||||
event_id: StringName
|
||||
) -> void:
|
||||
|
||||
if logic_engine == null:
|
||||
return
|
||||
|
||||
logic_engine.emit_event(
|
||||
source_id,
|
||||
event_id
|
||||
)
|
||||
|
||||
func _on_logic_action_requested(
|
||||
target_id: StringName,
|
||||
action_id: StringName,
|
||||
rule_id: StringName
|
||||
) -> void:
|
||||
|
||||
if room == null:
|
||||
return
|
||||
|
||||
#
|
||||
# First: direct room-device action.
|
||||
#
|
||||
var device := room.get_device(
|
||||
target_id
|
||||
)
|
||||
|
||||
if device != null:
|
||||
|
||||
_apply_device_action(
|
||||
device,
|
||||
action_id,
|
||||
rule_id
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
#
|
||||
# Second: cabinet hardware action.
|
||||
#
|
||||
var assignment := (
|
||||
scenario.get_assignment_for_cabinet(
|
||||
target_id
|
||||
)
|
||||
)
|
||||
|
||||
if assignment != null:
|
||||
|
||||
_activate_action(
|
||||
target_id,
|
||||
action_id,
|
||||
{
|
||||
"logic_rule": rule_id
|
||||
}
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
print(
|
||||
"[SIM] Unhandled logic action: ",
|
||||
target_id,
|
||||
".",
|
||||
action_id
|
||||
)
|
||||
|
||||
func _apply_device_action(
|
||||
device: RoomDeviceDefinition,
|
||||
action_id: StringName,
|
||||
_rule_id: StringName
|
||||
) -> void:
|
||||
|
||||
match action_id:
|
||||
|
||||
&"activate":
|
||||
_set_device_active(
|
||||
device.device_id,
|
||||
true
|
||||
)
|
||||
|
||||
_emit_device_event(
|
||||
device.device_id,
|
||||
&"activated"
|
||||
)
|
||||
|
||||
&"deactivate":
|
||||
_set_device_active(
|
||||
device.device_id,
|
||||
false
|
||||
)
|
||||
|
||||
_emit_device_event(
|
||||
device.device_id,
|
||||
&"deactivated"
|
||||
)
|
||||
|
||||
&"turn_on":
|
||||
_set_device_active(
|
||||
device.device_id,
|
||||
true
|
||||
)
|
||||
|
||||
_emit_device_event(
|
||||
device.device_id,
|
||||
&"turned_on"
|
||||
)
|
||||
|
||||
&"turn_off":
|
||||
_set_device_active(
|
||||
device.device_id,
|
||||
false
|
||||
)
|
||||
|
||||
_emit_device_event(
|
||||
device.device_id,
|
||||
&"turned_off"
|
||||
)
|
||||
|
||||
&"unlock":
|
||||
_set_device_active(
|
||||
device.device_id,
|
||||
true
|
||||
)
|
||||
|
||||
_emit_device_event(
|
||||
device.device_id,
|
||||
&"unlocked"
|
||||
)
|
||||
|
||||
&"lock":
|
||||
_set_device_active(
|
||||
device.device_id,
|
||||
false
|
||||
)
|
||||
|
||||
_emit_device_event(
|
||||
device.device_id,
|
||||
&"locked"
|
||||
)
|
||||
|
||||
_:
|
||||
print(
|
||||
"[SIM] Unsupported device action: ",
|
||||
device.device_id,
|
||||
".",
|
||||
action_id
|
||||
)
|
||||
|
||||
func _set_device_active(
|
||||
device_id: StringName,
|
||||
active: bool
|
||||
) -> void:
|
||||
|
||||
var previous_active := bool(
|
||||
simulated_device_states.get(
|
||||
device_id,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
simulated_device_states[
|
||||
device_id
|
||||
] = active
|
||||
|
||||
device_state_changed.emit(
|
||||
device_id,
|
||||
active
|
||||
)
|
||||
|
||||
#
|
||||
# Record the simulated physical-state transition.
|
||||
#
|
||||
if previous_active != active:
|
||||
|
||||
trace_entry_created.emit(
|
||||
{
|
||||
"type": &"device",
|
||||
"time": _get_simulation_time(),
|
||||
"device_id": device_id,
|
||||
"active": active,
|
||||
}
|
||||
)
|
||||
|
||||
func _emit_device_event(
|
||||
device_id: StringName,
|
||||
event_id: StringName
|
||||
) -> void:
|
||||
|
||||
if logic_engine == null:
|
||||
return
|
||||
|
||||
logic_engine.emit_event(
|
||||
device_id,
|
||||
event_id
|
||||
)
|
||||
|
||||
func _on_logic_trace_entry_created(
|
||||
entry: Dictionary
|
||||
) -> void:
|
||||
|
||||
var timed_entry := (
|
||||
entry.duplicate(true)
|
||||
)
|
||||
|
||||
timed_entry["time"] = (
|
||||
_get_simulation_time()
|
||||
)
|
||||
|
||||
print(
|
||||
"[SIM TRACE] ",
|
||||
timed_entry
|
||||
)
|
||||
|
||||
trace_entry_created.emit(
|
||||
timed_entry
|
||||
)
|
||||
|
||||
func _propagate_hardware_action_to_devices(
|
||||
cabinet_id: StringName,
|
||||
action_id: StringName,
|
||||
active: bool,
|
||||
context: Dictionary
|
||||
) -> void:
|
||||
|
||||
if room == null:
|
||||
return
|
||||
|
||||
for binding in room.bindings:
|
||||
|
||||
if binding == null:
|
||||
continue
|
||||
|
||||
if binding.cabinet_id != cabinet_id:
|
||||
continue
|
||||
|
||||
if binding.hardware_action_id != action_id:
|
||||
continue
|
||||
|
||||
var device := room.get_device(
|
||||
binding.device_id
|
||||
)
|
||||
|
||||
if device == null:
|
||||
continue
|
||||
|
||||
_set_device_active(
|
||||
device.device_id,
|
||||
active
|
||||
)
|
||||
|
||||
print(
|
||||
"[SIM DEVICE PATH] ",
|
||||
cabinet_id,
|
||||
".",
|
||||
action_id,
|
||||
" -> ",
|
||||
device.device_id,
|
||||
" active=",
|
||||
active,
|
||||
" context=",
|
||||
context
|
||||
)
|
||||
|
||||
if active:
|
||||
|
||||
_emit_device_event(
|
||||
device.device_id,
|
||||
&"activated"
|
||||
)
|
||||
|
||||
else:
|
||||
|
||||
_emit_device_event(
|
||||
device.device_id,
|
||||
&"deactivated"
|
||||
)
|
||||
|
||||
func _on_simulated_pin_state_changed(
|
||||
cabinet_id: StringName,
|
||||
_gpio_pin: int,
|
||||
active: bool,
|
||||
action_id: StringName,
|
||||
context: Dictionary
|
||||
) -> void:
|
||||
|
||||
_propagate_hardware_action_to_devices(
|
||||
cabinet_id,
|
||||
action_id,
|
||||
active,
|
||||
context
|
||||
)
|
||||
|
||||
func _on_hardware_trace_entry_created(
|
||||
entry: Dictionary
|
||||
) -> void:
|
||||
|
||||
var timed_entry := (
|
||||
entry.duplicate(true)
|
||||
)
|
||||
|
||||
timed_entry["time"] = (
|
||||
_get_simulation_time()
|
||||
)
|
||||
|
||||
print(
|
||||
"[GPIO SIM] ",
|
||||
timed_entry
|
||||
)
|
||||
|
||||
trace_entry_created.emit(
|
||||
timed_entry
|
||||
)
|
||||
|
||||
func _process_pending_hardware_deactivations() -> void:
|
||||
|
||||
if pending_hardware_deactivations.is_empty():
|
||||
return
|
||||
|
||||
var ready: Array[Dictionary] = []
|
||||
var remaining: Array[Dictionary] = []
|
||||
|
||||
for pending in pending_hardware_deactivations:
|
||||
|
||||
var execute_at: float = (
|
||||
pending.get(
|
||||
"execute_at",
|
||||
0.0
|
||||
)
|
||||
)
|
||||
|
||||
if execute_at <= _get_simulation_time():
|
||||
ready.append(
|
||||
pending
|
||||
)
|
||||
else:
|
||||
remaining.append(
|
||||
pending
|
||||
)
|
||||
|
||||
pending_hardware_deactivations = remaining
|
||||
|
||||
for pending in ready:
|
||||
|
||||
_deactivate_hardware_action(
|
||||
pending.get(
|
||||
"cabinet_id",
|
||||
&""
|
||||
),
|
||||
|
||||
pending.get(
|
||||
"action_id",
|
||||
&""
|
||||
),
|
||||
|
||||
pending.get(
|
||||
"context",
|
||||
{}
|
||||
)
|
||||
)
|
||||
|
||||
func _deactivate_hardware_action(
|
||||
cabinet_id: StringName,
|
||||
action_id: StringName,
|
||||
context: Dictionary
|
||||
) -> void:
|
||||
|
||||
if scenario == null:
|
||||
return
|
||||
|
||||
var assignment := (
|
||||
scenario.get_assignment_for_cabinet(
|
||||
cabinet_id
|
||||
)
|
||||
)
|
||||
|
||||
if assignment == null:
|
||||
return
|
||||
|
||||
if assignment.cabinet == null:
|
||||
return
|
||||
|
||||
if assignment.cabinet.hardware_config == null:
|
||||
return
|
||||
|
||||
var action := (
|
||||
assignment.cabinet.hardware_config.get_action(
|
||||
action_id
|
||||
)
|
||||
)
|
||||
|
||||
if action == null:
|
||||
return
|
||||
|
||||
action_deactivated.emit(
|
||||
cabinet_id,
|
||||
action_id,
|
||||
context
|
||||
)
|
||||
|
||||
if hardware_backend != null:
|
||||
|
||||
hardware_backend.deactivate_action(
|
||||
cabinet_id,
|
||||
action,
|
||||
context
|
||||
)
|
||||
|
||||
func set_paused(
|
||||
value: bool
|
||||
) -> void:
|
||||
|
||||
paused = value
|
||||
|
||||
|
||||
func is_paused() -> bool:
|
||||
|
||||
return paused
|
||||
|
||||
|
||||
func step(
|
||||
delta_seconds: float
|
||||
) -> void:
|
||||
|
||||
if delta_seconds <= 0.0:
|
||||
return
|
||||
|
||||
_advance_internal(
|
||||
delta_seconds
|
||||
)
|
||||
|
||||
|
||||
func reset_simulation() -> void:
|
||||
|
||||
pending_sequence_steps.clear()
|
||||
|
||||
active_sequence = null
|
||||
sequence_running = false
|
||||
sequence_start_time = 0.0
|
||||
sequence_settling = false
|
||||
|
||||
pending_hardware_deactivations.clear()
|
||||
simulated_device_states.clear()
|
||||
|
||||
if logic_engine != null:
|
||||
logic_engine.reset()
|
||||
|
||||
if hardware_backend != null:
|
||||
hardware_backend.reset()
|
||||
|
||||
paused = false
|
||||
|
||||
func _advance_internal(
|
||||
delta_seconds: float
|
||||
) -> void:
|
||||
|
||||
if delta_seconds <= 0.0:
|
||||
return
|
||||
|
||||
if logic_engine == null:
|
||||
return
|
||||
|
||||
logic_engine.advance(
|
||||
delta_seconds
|
||||
)
|
||||
|
||||
_process_pending_sequence_steps()
|
||||
|
||||
_process_pending_hardware_deactivations()
|
||||
|
||||
_finish_sequence_if_ready()
|
||||
|
||||
func _process_pending_sequence_steps() -> void:
|
||||
|
||||
if not sequence_running:
|
||||
return
|
||||
|
||||
if pending_sequence_steps.is_empty():
|
||||
|
||||
_finish_sequence_if_ready()
|
||||
|
||||
return
|
||||
|
||||
_finish_sequence_if_ready()
|
||||
|
||||
var current_time := (
|
||||
_get_simulation_time()
|
||||
)
|
||||
|
||||
var ready: Array[Dictionary] = []
|
||||
var remaining: Array[Dictionary] = []
|
||||
|
||||
for pending in pending_sequence_steps:
|
||||
|
||||
var execute_at := float(
|
||||
pending.get(
|
||||
"execute_at",
|
||||
0.0
|
||||
)
|
||||
)
|
||||
|
||||
if execute_at <= current_time:
|
||||
|
||||
ready.append(
|
||||
pending
|
||||
)
|
||||
|
||||
else:
|
||||
|
||||
remaining.append(
|
||||
pending
|
||||
)
|
||||
|
||||
pending_sequence_steps = remaining
|
||||
|
||||
for pending in ready:
|
||||
|
||||
var step := (
|
||||
pending.get(
|
||||
"step"
|
||||
)
|
||||
as TestSequenceStep
|
||||
)
|
||||
|
||||
if step == null:
|
||||
continue
|
||||
|
||||
_execute_sequence_step(
|
||||
step
|
||||
)
|
||||
|
||||
_finish_sequence_if_ready()
|
||||
|
||||
func _execute_sequence_step(
|
||||
step: TestSequenceStep
|
||||
) -> void:
|
||||
|
||||
trace_entry_created.emit(
|
||||
{
|
||||
"type": &"input",
|
||||
"time": _get_simulation_time(),
|
||||
"source_id": step.source_id,
|
||||
"event_id": step.event_id,
|
||||
"note": step.note,
|
||||
}
|
||||
)
|
||||
|
||||
#
|
||||
# If the source is a scenario cabinet, this is a
|
||||
# game/cabinet event and must travel through the
|
||||
# existing scenario mapping as well as room logic.
|
||||
#
|
||||
if scenario != null:
|
||||
|
||||
var assignment := (
|
||||
scenario.get_assignment_for_cabinet(
|
||||
step.source_id
|
||||
)
|
||||
)
|
||||
|
||||
if assignment != null:
|
||||
|
||||
simulate_game_event(
|
||||
step.source_id,
|
||||
step.event_id
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
#
|
||||
# Otherwise this is a generic room/world input.
|
||||
#
|
||||
emit_room_event(
|
||||
step.source_id,
|
||||
step.event_id
|
||||
)
|
||||
|
||||
func _finish_sequence_if_ready() -> void:
|
||||
|
||||
if not sequence_running:
|
||||
return
|
||||
|
||||
#
|
||||
# Still waiting to inject authored inputs.
|
||||
#
|
||||
if not pending_sequence_steps.is_empty():
|
||||
return
|
||||
|
||||
#
|
||||
# All authored inputs have been injected.
|
||||
# Enter settling state once.
|
||||
#
|
||||
if not sequence_settling:
|
||||
|
||||
sequence_settling = true
|
||||
|
||||
if active_sequence != null:
|
||||
|
||||
trace_entry_created.emit(
|
||||
{
|
||||
"type": &"sequence",
|
||||
"time": _get_simulation_time(),
|
||||
"sequence_id": active_sequence.sequence_id,
|
||||
"display_name": active_sequence.display_name,
|
||||
"state": &"settling",
|
||||
}
|
||||
)
|
||||
|
||||
#
|
||||
# Room logic still has delayed work.
|
||||
#
|
||||
if (
|
||||
logic_engine != null
|
||||
and logic_engine.has_pending_actions()
|
||||
):
|
||||
return
|
||||
|
||||
#
|
||||
# Hardware pulses are still active.
|
||||
#
|
||||
if not pending_hardware_deactivations.is_empty():
|
||||
return
|
||||
|
||||
#
|
||||
# Everything has settled.
|
||||
#
|
||||
var completed_sequence := active_sequence
|
||||
|
||||
sequence_running = false
|
||||
sequence_settling = false
|
||||
active_sequence = null
|
||||
|
||||
if completed_sequence == null:
|
||||
return
|
||||
|
||||
trace_entry_created.emit(
|
||||
{
|
||||
"type": &"sequence",
|
||||
"time": _get_simulation_time(),
|
||||
"sequence_id": completed_sequence.sequence_id,
|
||||
"display_name": completed_sequence.display_name,
|
||||
"state": &"finished",
|
||||
}
|
||||
)
|
||||
|
||||
sequence_finished.emit(
|
||||
completed_sequence
|
||||
)
|
||||
|
||||
func stop_sequence() -> void:
|
||||
|
||||
if not sequence_running:
|
||||
return
|
||||
|
||||
pending_sequence_steps.clear()
|
||||
|
||||
sequence_running = false
|
||||
sequence_settling = false
|
||||
active_sequence = null
|
||||
|
||||
trace_entry_created.emit(
|
||||
{
|
||||
"type": &"sequence",
|
||||
"time": _get_simulation_time(),
|
||||
"state": &"stopped",
|
||||
}
|
||||
)
|
||||
|
||||
sequence_stopped.emit()
|
||||
@@ -0,0 +1 @@
|
||||
uid://cooxa42fh5jd
|
||||
@@ -0,0 +1,126 @@
|
||||
@tool
|
||||
class_name EscapeRoomEditorContext
|
||||
extends RefCounted
|
||||
|
||||
|
||||
signal room_changed(
|
||||
room: RoomDefinition
|
||||
)
|
||||
|
||||
signal scenario_changed(
|
||||
scenario: ScenarioDefinition
|
||||
)
|
||||
|
||||
signal selection_changed
|
||||
|
||||
|
||||
var database: ProjectDatabase
|
||||
|
||||
var source_room: RoomDefinition
|
||||
var source_scenario: ScenarioDefinition
|
||||
|
||||
var room_edit_session := RoomEditSession.new()
|
||||
var scenario_edit_session := ScenarioEditSession.new()
|
||||
|
||||
|
||||
func configure(
|
||||
project_database: ProjectDatabase,
|
||||
room: RoomDefinition
|
||||
) -> bool:
|
||||
|
||||
if project_database == null:
|
||||
push_error(
|
||||
"EscapeRoomEditorContext requires a ProjectDatabase."
|
||||
)
|
||||
return false
|
||||
|
||||
if room == null:
|
||||
push_error(
|
||||
"EscapeRoomEditorContext requires a RoomDefinition."
|
||||
)
|
||||
return false
|
||||
|
||||
database = project_database
|
||||
source_room = room
|
||||
|
||||
if not room_edit_session.room_changed.is_connected(
|
||||
_on_working_room_changed
|
||||
):
|
||||
room_edit_session.room_changed.connect(
|
||||
_on_working_room_changed
|
||||
)
|
||||
|
||||
if not room_edit_session.begin(
|
||||
source_room
|
||||
):
|
||||
return false
|
||||
if not scenario_edit_session.scenario_changed.is_connected(
|
||||
_on_working_scenario_changed
|
||||
):
|
||||
scenario_edit_session.scenario_changed.connect(
|
||||
_on_working_scenario_changed
|
||||
)
|
||||
|
||||
return true
|
||||
|
||||
func _on_working_scenario_changed(
|
||||
scenario: ScenarioDefinition
|
||||
) -> void:
|
||||
|
||||
scenario_changed.emit(
|
||||
scenario
|
||||
)
|
||||
|
||||
func open_scenario(
|
||||
scenario: ScenarioDefinition
|
||||
) -> bool:
|
||||
|
||||
if scenario == null:
|
||||
push_error(
|
||||
"Cannot open a null scenario."
|
||||
)
|
||||
return false
|
||||
|
||||
source_scenario = scenario
|
||||
|
||||
if not scenario_edit_session.begin(
|
||||
source_scenario
|
||||
):
|
||||
return false
|
||||
|
||||
scenario_changed.emit(
|
||||
scenario_edit_session.working_scenario
|
||||
)
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func get_room() -> RoomDefinition:
|
||||
return room_edit_session.working_room
|
||||
|
||||
|
||||
func get_scenario() -> ScenarioDefinition:
|
||||
return scenario_edit_session.working_scenario
|
||||
|
||||
|
||||
func save_room() -> bool:
|
||||
return room_edit_session.save()
|
||||
|
||||
|
||||
func revert_room() -> void:
|
||||
room_edit_session.revert()
|
||||
|
||||
|
||||
func save_scenario() -> bool:
|
||||
return scenario_edit_session.save()
|
||||
|
||||
|
||||
func revert_scenario() -> void:
|
||||
scenario_edit_session.revert()
|
||||
|
||||
|
||||
func _on_working_room_changed(
|
||||
room: RoomDefinition
|
||||
) -> void:
|
||||
|
||||
room_changed.emit(room)
|
||||
@@ -0,0 +1 @@
|
||||
uid://t82k7x32o5gc
|
||||
@@ -0,0 +1,72 @@
|
||||
@tool
|
||||
class_name EscapeRoomEditorSelection
|
||||
extends RefCounted
|
||||
|
||||
|
||||
signal changed
|
||||
|
||||
|
||||
var cabinet_id: StringName = &""
|
||||
var device_id: StringName = &""
|
||||
var event_id: StringName = &""
|
||||
var action_id: StringName = &""
|
||||
var wall_id: StringName = &""
|
||||
|
||||
|
||||
func clear() -> void:
|
||||
|
||||
_clear_values()
|
||||
changed.emit()
|
||||
|
||||
|
||||
func select_cabinet(
|
||||
id: StringName
|
||||
) -> void:
|
||||
|
||||
_clear_values()
|
||||
cabinet_id = id
|
||||
changed.emit()
|
||||
|
||||
|
||||
func select_device(
|
||||
id: StringName
|
||||
) -> void:
|
||||
|
||||
_clear_values()
|
||||
device_id = id
|
||||
changed.emit()
|
||||
|
||||
|
||||
func select_wall(
|
||||
id: StringName
|
||||
) -> void:
|
||||
|
||||
_clear_values()
|
||||
wall_id = id
|
||||
changed.emit()
|
||||
|
||||
|
||||
func select_logic_path(
|
||||
new_cabinet_id: StringName,
|
||||
new_event_id: StringName,
|
||||
new_action_id: StringName,
|
||||
new_device_id: StringName = &""
|
||||
) -> void:
|
||||
|
||||
_clear_values()
|
||||
|
||||
cabinet_id = new_cabinet_id
|
||||
event_id = new_event_id
|
||||
action_id = new_action_id
|
||||
device_id = new_device_id
|
||||
|
||||
changed.emit()
|
||||
|
||||
|
||||
func _clear_values() -> void:
|
||||
|
||||
cabinet_id = &""
|
||||
device_id = &""
|
||||
event_id = &""
|
||||
action_id = &""
|
||||
wall_id = &""
|
||||
@@ -0,0 +1 @@
|
||||
uid://bab3rbavt5u1f
|
||||
@@ -0,0 +1,25 @@
|
||||
class_name EscapeRoomSetupValidator
|
||||
|
||||
|
||||
static func validate(
|
||||
room: RoomDefinition,
|
||||
scenario: ScenarioDefinition,
|
||||
database: ProjectDatabase
|
||||
) -> ValidationResult:
|
||||
|
||||
var result := ValidationResult.new()
|
||||
|
||||
result.merge(
|
||||
RoomValidator.validate(
|
||||
room,
|
||||
database
|
||||
)
|
||||
)
|
||||
|
||||
result.merge(
|
||||
ScenarioValidator.validate(
|
||||
scenario
|
||||
)
|
||||
)
|
||||
|
||||
return result
|
||||
@@ -0,0 +1 @@
|
||||
uid://bjjc0dmjp54wr
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1 @@
|
||||
uid://jxob25ucisxl
|
||||
@@ -0,0 +1,677 @@
|
||||
@tool
|
||||
class_name SimulationTimeline
|
||||
extends VBoxContainer
|
||||
|
||||
signal pause_requested
|
||||
signal resume_requested
|
||||
signal step_requested(
|
||||
seconds: float
|
||||
)
|
||||
signal reset_requested
|
||||
|
||||
signal sequence_selected(
|
||||
index: int
|
||||
)
|
||||
|
||||
signal run_sequence_requested
|
||||
signal stop_sequence_requested
|
||||
signal replay_sequence_requested
|
||||
|
||||
var sequence_select: OptionButton
|
||||
var run_button: Button
|
||||
var stop_button: Button
|
||||
var replay_button: Button
|
||||
|
||||
var tree: Tree
|
||||
var clear_button: Button
|
||||
var count_label: Label
|
||||
|
||||
var _first_trace_time: float = -1.0
|
||||
var _entry_count: int = 0
|
||||
|
||||
var pause_button: Button
|
||||
var step_button: Button
|
||||
var reset_button: Button
|
||||
|
||||
var _paused: bool = false
|
||||
|
||||
func _ready() -> void:
|
||||
|
||||
if tree != null:
|
||||
return
|
||||
|
||||
_build_ui()
|
||||
|
||||
|
||||
func _build_ui() -> void:
|
||||
|
||||
var toolbar := HBoxContainer.new()
|
||||
|
||||
add_child(
|
||||
toolbar
|
||||
)
|
||||
|
||||
|
||||
var title := Label.new()
|
||||
|
||||
title.text = "Simulation Timeline"
|
||||
|
||||
title.size_flags_horizontal = (
|
||||
Control.SIZE_EXPAND_FILL
|
||||
)
|
||||
|
||||
toolbar.add_child(
|
||||
title
|
||||
)
|
||||
|
||||
|
||||
count_label = Label.new()
|
||||
|
||||
count_label.text = "0 events"
|
||||
|
||||
toolbar.add_child(
|
||||
count_label
|
||||
)
|
||||
|
||||
sequence_select = OptionButton.new()
|
||||
|
||||
sequence_select.custom_minimum_size.x = 180.0
|
||||
|
||||
sequence_select.item_selected.connect(
|
||||
func(index: int):
|
||||
sequence_selected.emit(
|
||||
index
|
||||
)
|
||||
)
|
||||
|
||||
toolbar.add_child(
|
||||
sequence_select
|
||||
)
|
||||
|
||||
|
||||
run_button = Button.new()
|
||||
|
||||
run_button.text = "Run"
|
||||
|
||||
run_button.pressed.connect(
|
||||
func():
|
||||
run_sequence_requested.emit()
|
||||
)
|
||||
|
||||
toolbar.add_child(
|
||||
run_button
|
||||
)
|
||||
|
||||
|
||||
stop_button = Button.new()
|
||||
|
||||
stop_button.text = "Stop"
|
||||
|
||||
stop_button.disabled = true
|
||||
|
||||
stop_button.pressed.connect(
|
||||
func():
|
||||
stop_sequence_requested.emit()
|
||||
)
|
||||
|
||||
toolbar.add_child(
|
||||
stop_button
|
||||
)
|
||||
|
||||
|
||||
replay_button = Button.new()
|
||||
|
||||
replay_button.text = "Replay"
|
||||
|
||||
replay_button.pressed.connect(
|
||||
func():
|
||||
replay_sequence_requested.emit()
|
||||
)
|
||||
|
||||
toolbar.add_child(
|
||||
replay_button
|
||||
)
|
||||
|
||||
pause_button = Button.new()
|
||||
|
||||
pause_button.text = "Pause"
|
||||
|
||||
pause_button.pressed.connect(
|
||||
_on_pause_button_pressed
|
||||
)
|
||||
|
||||
toolbar.add_child(
|
||||
pause_button
|
||||
)
|
||||
|
||||
|
||||
step_button = Button.new()
|
||||
|
||||
step_button.text = "Step 0.1s"
|
||||
|
||||
step_button.pressed.connect(
|
||||
func():
|
||||
step_requested.emit(
|
||||
0.1
|
||||
)
|
||||
)
|
||||
|
||||
toolbar.add_child(
|
||||
step_button
|
||||
)
|
||||
|
||||
|
||||
reset_button = Button.new()
|
||||
|
||||
reset_button.text = "Reset"
|
||||
|
||||
reset_button.pressed.connect(
|
||||
func():
|
||||
reset_requested.emit()
|
||||
)
|
||||
|
||||
toolbar.add_child(
|
||||
reset_button
|
||||
)
|
||||
|
||||
clear_button = Button.new()
|
||||
|
||||
clear_button.text = "Clear"
|
||||
|
||||
clear_button.pressed.connect(
|
||||
clear
|
||||
)
|
||||
|
||||
toolbar.add_child(
|
||||
clear_button
|
||||
)
|
||||
|
||||
|
||||
tree = Tree.new()
|
||||
|
||||
tree.size_flags_horizontal = (
|
||||
Control.SIZE_EXPAND_FILL
|
||||
)
|
||||
|
||||
tree.size_flags_vertical = (
|
||||
Control.SIZE_EXPAND_FILL
|
||||
)
|
||||
|
||||
tree.custom_minimum_size.y = 180.0
|
||||
|
||||
tree.columns = 4
|
||||
|
||||
tree.set_column_title(
|
||||
0,
|
||||
"Time"
|
||||
)
|
||||
|
||||
tree.set_column_title(
|
||||
1,
|
||||
"Type"
|
||||
)
|
||||
|
||||
tree.set_column_title(
|
||||
2,
|
||||
"Source / Target"
|
||||
)
|
||||
|
||||
tree.set_column_title(
|
||||
3,
|
||||
"Detail"
|
||||
)
|
||||
|
||||
tree.column_titles_visible = true
|
||||
|
||||
tree.set_column_expand(
|
||||
0,
|
||||
false
|
||||
)
|
||||
|
||||
tree.set_column_custom_minimum_width(
|
||||
0,
|
||||
80
|
||||
)
|
||||
|
||||
tree.set_column_expand(
|
||||
1,
|
||||
false
|
||||
)
|
||||
|
||||
tree.set_column_custom_minimum_width(
|
||||
1,
|
||||
90
|
||||
)
|
||||
|
||||
tree.set_column_expand(
|
||||
2,
|
||||
true
|
||||
)
|
||||
|
||||
tree.set_column_expand(
|
||||
3,
|
||||
true
|
||||
)
|
||||
|
||||
add_child(
|
||||
tree
|
||||
)
|
||||
|
||||
tree.create_item()
|
||||
set_paused(
|
||||
false
|
||||
)
|
||||
|
||||
func clear() -> void:
|
||||
|
||||
_first_trace_time = -1.0
|
||||
_entry_count = 0
|
||||
|
||||
if count_label != null:
|
||||
count_label.text = "0 events"
|
||||
|
||||
if tree == null:
|
||||
return
|
||||
|
||||
tree.clear()
|
||||
|
||||
tree.create_item()
|
||||
|
||||
|
||||
func add_trace_entry(
|
||||
entry: Dictionary
|
||||
) -> void:
|
||||
|
||||
if tree == null:
|
||||
_build_ui()
|
||||
|
||||
var absolute_time := float(
|
||||
entry.get(
|
||||
"time",
|
||||
0.0
|
||||
)
|
||||
)
|
||||
|
||||
if _first_trace_time < 0.0:
|
||||
_first_trace_time = absolute_time
|
||||
|
||||
var relative_time := (
|
||||
absolute_time
|
||||
- _first_trace_time
|
||||
)
|
||||
|
||||
var root := tree.get_root()
|
||||
|
||||
if root == null:
|
||||
root = tree.create_item()
|
||||
|
||||
var item := tree.create_item(
|
||||
root
|
||||
)
|
||||
|
||||
item.set_text(
|
||||
0,
|
||||
"%.3f" % relative_time
|
||||
)
|
||||
|
||||
var entry_type := StringName(
|
||||
entry.get(
|
||||
"type",
|
||||
&"unknown"
|
||||
)
|
||||
)
|
||||
|
||||
item.set_text(
|
||||
1,
|
||||
String(entry_type).to_upper()
|
||||
)
|
||||
|
||||
item.set_text(
|
||||
2,
|
||||
_get_subject_text(
|
||||
entry
|
||||
)
|
||||
)
|
||||
|
||||
item.set_text(
|
||||
3,
|
||||
_get_detail_text(
|
||||
entry
|
||||
)
|
||||
)
|
||||
|
||||
_entry_count += 1
|
||||
|
||||
if count_label != null:
|
||||
|
||||
count_label.text = (
|
||||
"%d events"
|
||||
% _entry_count
|
||||
)
|
||||
|
||||
tree.scroll_to_item(
|
||||
item
|
||||
)
|
||||
|
||||
|
||||
func _get_subject_text(
|
||||
entry: Dictionary
|
||||
) -> String:
|
||||
|
||||
var entry_type := StringName(
|
||||
entry.get(
|
||||
"type",
|
||||
&""
|
||||
)
|
||||
)
|
||||
|
||||
match entry_type:
|
||||
|
||||
&"event":
|
||||
return String(
|
||||
entry.get(
|
||||
"source_id",
|
||||
&""
|
||||
)
|
||||
)
|
||||
|
||||
&"rule":
|
||||
return String(
|
||||
entry.get(
|
||||
"rule_id",
|
||||
&""
|
||||
)
|
||||
)
|
||||
|
||||
&"action":
|
||||
return String(
|
||||
entry.get(
|
||||
"target_id",
|
||||
&""
|
||||
)
|
||||
)
|
||||
|
||||
&"gpio":
|
||||
return String(
|
||||
entry.get(
|
||||
"cabinet_id",
|
||||
&""
|
||||
)
|
||||
)
|
||||
|
||||
&"device":
|
||||
return String(
|
||||
entry.get(
|
||||
"device_id",
|
||||
&""
|
||||
)
|
||||
)
|
||||
|
||||
&"input":
|
||||
return String(
|
||||
entry.get(
|
||||
"source_id",
|
||||
&""
|
||||
)
|
||||
)
|
||||
|
||||
&"sequence":
|
||||
return String(
|
||||
entry.get(
|
||||
"display_name",
|
||||
entry.get(
|
||||
"sequence_id",
|
||||
&""
|
||||
)
|
||||
)
|
||||
)
|
||||
_:
|
||||
return ""
|
||||
|
||||
|
||||
func _get_detail_text(
|
||||
entry: Dictionary
|
||||
) -> String:
|
||||
|
||||
var entry_type := StringName(
|
||||
entry.get(
|
||||
"type",
|
||||
&""
|
||||
)
|
||||
)
|
||||
|
||||
match entry_type:
|
||||
|
||||
&"event":
|
||||
|
||||
return String(
|
||||
entry.get(
|
||||
"event_id",
|
||||
&""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
&"rule":
|
||||
|
||||
var target_id := String(
|
||||
entry.get(
|
||||
"target_id",
|
||||
&""
|
||||
)
|
||||
)
|
||||
|
||||
var action_id := String(
|
||||
entry.get(
|
||||
"action_id",
|
||||
&""
|
||||
)
|
||||
)
|
||||
|
||||
var delay := float(
|
||||
entry.get(
|
||||
"delay_seconds",
|
||||
0.0
|
||||
)
|
||||
)
|
||||
|
||||
if delay > 0.0:
|
||||
|
||||
return (
|
||||
"→ %s.%s after %.3fs"
|
||||
% [
|
||||
target_id,
|
||||
action_id,
|
||||
delay
|
||||
]
|
||||
)
|
||||
|
||||
return (
|
||||
"→ %s.%s"
|
||||
% [
|
||||
target_id,
|
||||
action_id
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
&"action":
|
||||
|
||||
return String(
|
||||
entry.get(
|
||||
"action_id",
|
||||
&""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
&"gpio":
|
||||
|
||||
var pin := int(
|
||||
entry.get(
|
||||
"gpio_pin",
|
||||
-1
|
||||
)
|
||||
)
|
||||
|
||||
var electrical_state := bool(
|
||||
entry.get(
|
||||
"electrical_state",
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
var action_id := String(
|
||||
entry.get(
|
||||
"action_id",
|
||||
&""
|
||||
)
|
||||
)
|
||||
|
||||
var level := "LOW"
|
||||
|
||||
if electrical_state:
|
||||
level = "HIGH"
|
||||
|
||||
return (
|
||||
"GPIO %d %s (%s)"
|
||||
% [
|
||||
pin,
|
||||
level,
|
||||
action_id
|
||||
]
|
||||
)
|
||||
|
||||
&"device":
|
||||
|
||||
var active := bool(
|
||||
entry.get(
|
||||
"active",
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
if active:
|
||||
return "ACTIVE"
|
||||
|
||||
return "INACTIVE"
|
||||
|
||||
&"input":
|
||||
|
||||
var event_id := String(
|
||||
entry.get(
|
||||
"event_id",
|
||||
&""
|
||||
)
|
||||
)
|
||||
|
||||
var note := String(
|
||||
entry.get(
|
||||
"note",
|
||||
""
|
||||
)
|
||||
)
|
||||
|
||||
if not note.is_empty():
|
||||
|
||||
return (
|
||||
"%s — %s"
|
||||
% [
|
||||
event_id,
|
||||
note
|
||||
]
|
||||
)
|
||||
|
||||
return event_id
|
||||
|
||||
|
||||
&"sequence":
|
||||
|
||||
var state := String(
|
||||
entry.get(
|
||||
"state",
|
||||
&""
|
||||
)
|
||||
)
|
||||
|
||||
return state.to_upper()
|
||||
_:
|
||||
return str(
|
||||
entry
|
||||
)
|
||||
|
||||
func _on_pause_button_pressed() -> void:
|
||||
|
||||
if _paused:
|
||||
|
||||
resume_requested.emit()
|
||||
|
||||
else:
|
||||
|
||||
pause_requested.emit()
|
||||
|
||||
func set_paused(
|
||||
value: bool
|
||||
) -> void:
|
||||
|
||||
_paused = value
|
||||
|
||||
if pause_button != null:
|
||||
|
||||
if _paused:
|
||||
pause_button.text = "Resume"
|
||||
else:
|
||||
pause_button.text = "Pause"
|
||||
|
||||
if step_button != null:
|
||||
step_button.disabled = not _paused
|
||||
|
||||
func set_sequences(
|
||||
sequences: Array[TestSequence]
|
||||
) -> void:
|
||||
|
||||
if sequence_select == null:
|
||||
return
|
||||
|
||||
sequence_select.clear()
|
||||
|
||||
for sequence in sequences:
|
||||
|
||||
if sequence == null:
|
||||
continue
|
||||
|
||||
var label := (
|
||||
sequence.display_name
|
||||
)
|
||||
|
||||
if label.is_empty():
|
||||
label = String(
|
||||
sequence.sequence_id
|
||||
)
|
||||
|
||||
sequence_select.add_item(
|
||||
label
|
||||
)
|
||||
|
||||
if sequence_select.item_count > 0:
|
||||
|
||||
sequence_select.select(
|
||||
0
|
||||
)
|
||||
|
||||
|
||||
func set_sequence_running(
|
||||
running: bool
|
||||
) -> void:
|
||||
|
||||
if run_button != null:
|
||||
run_button.disabled = running
|
||||
|
||||
if stop_button != null:
|
||||
stop_button.disabled = not running
|
||||
|
||||
if replay_button != null:
|
||||
replay_button.disabled = running
|
||||
|
||||
if sequence_select != null:
|
||||
sequence_select.disabled = running
|
||||
@@ -0,0 +1 @@
|
||||
uid://b0tn15y67fac4
|
||||
Reference in new issue
Block a user