244 lines
3.3 KiB
GDScript
244 lines
3.3 KiB
GDScript
class_name RoomLogicEngine
|
|
extends RefCounted
|
|
|
|
|
|
signal event_received(
|
|
source_id: StringName,
|
|
event_id: StringName
|
|
)
|
|
|
|
signal rule_triggered(
|
|
rule_id: StringName,
|
|
source_id: StringName,
|
|
event_id: StringName,
|
|
target_id: StringName,
|
|
action_id: StringName
|
|
)
|
|
|
|
signal action_requested(
|
|
target_id: StringName,
|
|
action_id: StringName,
|
|
rule_id: StringName
|
|
)
|
|
|
|
signal trace_entry_created(
|
|
entry: Dictionary
|
|
)
|
|
|
|
|
|
var room: RoomDefinition
|
|
|
|
var _pending_actions: Array[Dictionary] = []
|
|
var _simulation_time: float = 0.0
|
|
|
|
|
|
func configure(
|
|
room_definition: RoomDefinition
|
|
) -> void:
|
|
|
|
room = room_definition
|
|
reset()
|
|
|
|
|
|
func reset() -> void:
|
|
|
|
_pending_actions.clear()
|
|
_simulation_time = 0.0
|
|
|
|
|
|
func get_simulation_time() -> float:
|
|
|
|
return _simulation_time
|
|
|
|
|
|
func emit_event(
|
|
source_id: StringName,
|
|
event_id: StringName
|
|
) -> void:
|
|
|
|
if room == null:
|
|
return
|
|
|
|
event_received.emit(
|
|
source_id,
|
|
event_id
|
|
)
|
|
|
|
_create_trace_entry(
|
|
&"event",
|
|
{
|
|
"source_id": source_id,
|
|
"event_id": event_id,
|
|
}
|
|
)
|
|
|
|
for rule in room.logic_rules:
|
|
|
|
if rule == null:
|
|
continue
|
|
|
|
if rule.source_id != source_id:
|
|
continue
|
|
|
|
if rule.event_id != event_id:
|
|
continue
|
|
|
|
_trigger_rule(
|
|
rule
|
|
)
|
|
|
|
|
|
func advance(
|
|
delta_seconds: float
|
|
) -> void:
|
|
|
|
if delta_seconds <= 0.0:
|
|
return
|
|
|
|
_simulation_time += delta_seconds
|
|
|
|
_process_pending_actions()
|
|
|
|
|
|
func _trigger_rule(
|
|
rule: RoomLogicRule
|
|
) -> void:
|
|
|
|
rule_triggered.emit(
|
|
rule.rule_id,
|
|
rule.source_id,
|
|
rule.event_id,
|
|
rule.target_id,
|
|
rule.action_id
|
|
)
|
|
|
|
_create_trace_entry(
|
|
&"rule",
|
|
{
|
|
"rule_id": rule.rule_id,
|
|
"source_id": rule.source_id,
|
|
"event_id": rule.event_id,
|
|
"target_id": rule.target_id,
|
|
"action_id": rule.action_id,
|
|
"delay_seconds": rule.delay_seconds,
|
|
}
|
|
)
|
|
|
|
if rule.delay_seconds <= 0.0:
|
|
|
|
_request_action(
|
|
rule.target_id,
|
|
rule.action_id,
|
|
rule.rule_id
|
|
)
|
|
|
|
return
|
|
|
|
_pending_actions.append(
|
|
{
|
|
"execute_at": (
|
|
_simulation_time
|
|
+ rule.delay_seconds
|
|
),
|
|
|
|
"target_id": (
|
|
rule.target_id
|
|
),
|
|
|
|
"action_id": (
|
|
rule.action_id
|
|
),
|
|
|
|
"rule_id": (
|
|
rule.rule_id
|
|
),
|
|
}
|
|
)
|
|
|
|
|
|
func _process_pending_actions() -> void:
|
|
|
|
if _pending_actions.is_empty():
|
|
return
|
|
|
|
var ready_actions: Array[Dictionary] = []
|
|
var remaining_actions: Array[Dictionary] = []
|
|
|
|
for pending in _pending_actions:
|
|
|
|
var execute_at: float = (
|
|
pending.get(
|
|
"execute_at",
|
|
0.0
|
|
)
|
|
)
|
|
|
|
if execute_at <= _simulation_time:
|
|
ready_actions.append(
|
|
pending
|
|
)
|
|
else:
|
|
remaining_actions.append(
|
|
pending
|
|
)
|
|
|
|
_pending_actions = remaining_actions
|
|
|
|
for pending in ready_actions:
|
|
|
|
_request_action(
|
|
pending.get(
|
|
"target_id",
|
|
&""
|
|
),
|
|
pending.get(
|
|
"action_id",
|
|
&""
|
|
),
|
|
pending.get(
|
|
"rule_id",
|
|
&""
|
|
)
|
|
)
|
|
|
|
|
|
func _request_action(
|
|
target_id: StringName,
|
|
action_id: StringName,
|
|
rule_id: StringName
|
|
) -> void:
|
|
|
|
_create_trace_entry(
|
|
&"action",
|
|
{
|
|
"target_id": target_id,
|
|
"action_id": action_id,
|
|
"rule_id": rule_id,
|
|
}
|
|
)
|
|
|
|
action_requested.emit(
|
|
target_id,
|
|
action_id,
|
|
rule_id
|
|
)
|
|
|
|
|
|
func _create_trace_entry(
|
|
entry_type: StringName,
|
|
data: Dictionary
|
|
) -> void:
|
|
|
|
var entry := data.duplicate()
|
|
|
|
entry["type"] = entry_type
|
|
entry["time"] = _simulation_time
|
|
|
|
trace_entry_created.emit(
|
|
entry
|
|
)
|
|
|
|
func has_pending_actions() -> bool:
|
|
|
|
return not _pending_actions.is_empty()
|