refactor: separate action system responsibilities
This commit is contained in:
+33
-165
@@ -6,11 +6,6 @@ const DEBUG_LOGS := true
|
||||
@export var simulation_manager: Node
|
||||
@export var active_npcs_parent: Node3D
|
||||
|
||||
@export var guard_zone: Marker3D
|
||||
@export var study_zone: Marker3D
|
||||
@export var rest_zone: Marker3D
|
||||
@export var food_zone: Marker3D
|
||||
|
||||
var active_npc_visuals := {}
|
||||
|
||||
func debug_log(message: String) -> void:
|
||||
@@ -23,227 +18,100 @@ func _ready() -> void:
|
||||
func initialize_world_view() -> void:
|
||||
await get_tree().physics_frame
|
||||
spawn_initial_npcs()
|
||||
|
||||
if simulation_manager.has_signal("npc_task_changed"):
|
||||
simulation_manager.npc_task_changed.connect(_on_npc_task_changed)
|
||||
if simulation_manager.has_signal("npc_target_requested"):
|
||||
simulation_manager.npc_target_requested.connect(
|
||||
_on_npc_target_requested
|
||||
)
|
||||
else:
|
||||
push_error("WorldViewManager: SimulationManager has no npc_task_changed signal")
|
||||
|
||||
push_error("WorldViewManager: missing npc_target_requested signal")
|
||||
if simulation_manager.has_signal("npc_travel_requested"):
|
||||
simulation_manager.npc_travel_requested.connect(
|
||||
_on_npc_travel_requested
|
||||
)
|
||||
else:
|
||||
push_error("WorldViewManager: missing npc_travel_requested signal")
|
||||
if simulation_manager.has_signal("npc_died"):
|
||||
simulation_manager.npc_died.connect(_on_npc_died)
|
||||
else:
|
||||
push_error("WorldViewManager: SimulationManager has no npc_died signal")
|
||||
|
||||
update_npc_targets()
|
||||
request_current_targets()
|
||||
|
||||
func spawn_initial_npcs() -> void:
|
||||
if simulation_manager == null:
|
||||
push_error("WorldViewManager: simulation_manager is missing")
|
||||
return
|
||||
|
||||
if npc_visual_scene == null:
|
||||
push_error("WorldViewManager: npc_visual_scene is missing")
|
||||
return
|
||||
|
||||
if active_npcs_parent == null:
|
||||
push_error("WorldViewManager: active_npcs_parent is missing")
|
||||
return
|
||||
|
||||
debug_log("Spawning NPC visuals. Count: %s" % simulation_manager.npcs.size())
|
||||
|
||||
for npc in simulation_manager.npcs:
|
||||
spawn_npc_visual(npc)
|
||||
|
||||
func spawn_npc_visual(npc: SimNPC) -> void:
|
||||
if active_npc_visuals.has(npc.id):
|
||||
return
|
||||
|
||||
var visual = npc_visual_scene.instantiate()
|
||||
active_npcs_parent.add_child(visual)
|
||||
|
||||
visual.global_position = npc.position
|
||||
visual.setup_from_sim(npc)
|
||||
|
||||
if visual.has_signal("arrived_at_target"):
|
||||
visual.arrived_at_target.connect(_on_npc_visual_arrived)
|
||||
else:
|
||||
push_error("WorldViewManager: NPCVisual has no arrived_at_target signal")
|
||||
|
||||
if visual.has_signal("navigation_failed"):
|
||||
visual.navigation_failed.connect(_on_npc_visual_navigation_failed)
|
||||
else:
|
||||
push_error("WorldViewManager: NPCVisual has no navigation_failed signal")
|
||||
|
||||
active_npc_visuals[npc.id] = visual
|
||||
debug_log("Spawned visual for %s at %s" % [npc.npc_name, npc.position])
|
||||
|
||||
func update_npc_targets() -> void:
|
||||
if simulation_manager == null:
|
||||
return
|
||||
|
||||
func request_current_targets() -> void:
|
||||
for npc in simulation_manager.npcs:
|
||||
if not active_npc_visuals.has(npc.id):
|
||||
if npc.task_state != SimNPC.TASK_STATE_TRAVELING:
|
||||
continue
|
||||
_on_npc_target_requested(npc)
|
||||
|
||||
var visual = active_npc_visuals[npc.id]
|
||||
var task = npc.current_task
|
||||
if task in [
|
||||
&"",
|
||||
SimulationIds.ACTION_IDLE,
|
||||
SimulationIds.ACTION_DEAD
|
||||
]:
|
||||
continue
|
||||
|
||||
var resource_pos = _try_get_resource_target(npc, npc.current_task)
|
||||
if resource_pos != null:
|
||||
visual.set_target_position(resource_pos)
|
||||
continue
|
||||
|
||||
if task == SimulationIds.ACTION_WANDER:
|
||||
var offset := _get_wander_offset(npc.id)
|
||||
visual.set_target_position(visual.global_position + offset)
|
||||
continue
|
||||
|
||||
var definition := SimulationDefinitions.get_action(task)
|
||||
if (
|
||||
definition != null
|
||||
and definition.target_type == SimulationIds.TARGET_RESOURCE
|
||||
):
|
||||
if simulation_manager.has_method("notify_npc_target_unavailable"):
|
||||
simulation_manager.notify_npc_target_unavailable(npc.id)
|
||||
continue
|
||||
|
||||
var target = get_target_for_task(task)
|
||||
|
||||
if target == null:
|
||||
debug_log("No target for task: %s" % task)
|
||||
continue
|
||||
|
||||
visual.set_target_position(target.global_position)
|
||||
|
||||
func get_target_for_task(task: StringName) -> Marker3D:
|
||||
match task:
|
||||
SimulationIds.ACTION_PATROL:
|
||||
return guard_zone
|
||||
SimulationIds.ACTION_STUDY:
|
||||
return study_zone
|
||||
SimulationIds.ACTION_REST:
|
||||
return rest_zone
|
||||
SimulationIds.ACTION_EAT:
|
||||
return food_zone
|
||||
_:
|
||||
return rest_zone
|
||||
|
||||
func _try_get_resource_target(npc: SimNPC, task: StringName) -> Variant:
|
||||
var definition := SimulationDefinitions.get_action(task)
|
||||
if (
|
||||
definition == null
|
||||
or definition.target_type != SimulationIds.TARGET_RESOURCE
|
||||
):
|
||||
return null
|
||||
|
||||
func _on_npc_target_requested(npc: SimNPC) -> void:
|
||||
var visual = active_npc_visuals.get(npc.id) as Node3D
|
||||
if visual == null:
|
||||
return null
|
||||
|
||||
if not simulation_manager.has_method("acquire_resource_target"):
|
||||
push_error("WorldViewManager: SimulationManager cannot acquire resources")
|
||||
return null
|
||||
var node: ResourceNode = simulation_manager.acquire_resource_target(
|
||||
definition.resource_action_id,
|
||||
return
|
||||
if not simulation_manager.resolve_npc_target(
|
||||
npc.id,
|
||||
visual.global_position
|
||||
)
|
||||
if node == null:
|
||||
debug_log("No available resource node for %s" % task)
|
||||
return null
|
||||
|
||||
npc.target_id = node.node_id
|
||||
debug_log("%s reserved %s for %s" % [npc.npc_name, node.node_id, task])
|
||||
return node.interaction_point.global_position
|
||||
|
||||
func _on_npc_task_changed(
|
||||
npc: SimNPC,
|
||||
old_task: StringName,
|
||||
new_task: StringName
|
||||
) -> void:
|
||||
if DEBUG_LOGS:
|
||||
debug_log("%s changed task: %s -> %s" % [npc.npc_name, old_task, new_task])
|
||||
|
||||
if not active_npc_visuals.has(npc.id):
|
||||
return
|
||||
|
||||
if new_task in [
|
||||
&"",
|
||||
SimulationIds.ACTION_IDLE,
|
||||
SimulationIds.ACTION_DEAD
|
||||
]:
|
||||
return
|
||||
|
||||
var visual = active_npc_visuals[npc.id]
|
||||
var resource_pos = _try_get_resource_target(npc, new_task)
|
||||
if resource_pos != null:
|
||||
visual.set_target_position(resource_pos)
|
||||
return
|
||||
|
||||
if new_task == SimulationIds.ACTION_WANDER:
|
||||
var offset := _get_wander_offset(npc.id)
|
||||
visual.set_target_position(visual.global_position + offset)
|
||||
return
|
||||
|
||||
var definition := SimulationDefinitions.get_action(new_task)
|
||||
if (
|
||||
definition != null
|
||||
and definition.target_type == SimulationIds.TARGET_RESOURCE
|
||||
):
|
||||
if simulation_manager.has_method("notify_npc_target_unavailable"):
|
||||
simulation_manager.notify_npc_target_unavailable(npc.id)
|
||||
else:
|
||||
push_error("WorldViewManager: SimulationManager cannot handle unavailable targets")
|
||||
return
|
||||
|
||||
var target := get_target_for_task(new_task)
|
||||
|
||||
if target != null:
|
||||
visual.set_target_position(target.global_position)
|
||||
debug_log("Target resolution failed for %s" % npc.npc_name)
|
||||
|
||||
func _on_npc_travel_requested(
|
||||
npc: SimNPC,
|
||||
target_position: Vector3
|
||||
) -> void:
|
||||
var visual = active_npc_visuals.get(npc.id)
|
||||
if visual == null:
|
||||
return
|
||||
visual.set_target_position(target_position)
|
||||
|
||||
func _get_wander_offset(npc_id: int) -> Vector3:
|
||||
if simulation_manager != null and simulation_manager.has_method("get_wander_offset"):
|
||||
return simulation_manager.get_wander_offset(npc_id)
|
||||
push_error("WorldViewManager: SimulationManager cannot provide deterministic wander offsets")
|
||||
return Vector3.ZERO
|
||||
|
||||
func _on_npc_visual_arrived(sim_id: int) -> void:
|
||||
debug_log("NPC visual arrived. sim_id=%s" % sim_id)
|
||||
|
||||
if simulation_manager == null:
|
||||
push_error("WorldViewManager: simulation_manager missing during arrival report")
|
||||
push_error("WorldViewManager: simulation_manager missing during arrival")
|
||||
return
|
||||
|
||||
if simulation_manager.has_method("notify_npc_arrived"):
|
||||
simulation_manager.notify_npc_arrived(sim_id)
|
||||
else:
|
||||
push_error("WorldViewManager: SimulationManager has no notify_npc_arrived method")
|
||||
simulation_manager.notify_npc_arrived(sim_id)
|
||||
|
||||
func _on_npc_visual_navigation_failed(sim_id: int) -> void:
|
||||
debug_log("NPC visual navigation failed. sim_id=%s" % sim_id)
|
||||
|
||||
if simulation_manager == null:
|
||||
push_error("WorldViewManager: simulation_manager missing during navigation failure")
|
||||
push_error("WorldViewManager: simulation_manager missing during failure")
|
||||
return
|
||||
|
||||
if simulation_manager.has_method("notify_npc_navigation_failed"):
|
||||
simulation_manager.notify_npc_navigation_failed(sim_id)
|
||||
else:
|
||||
push_error("WorldViewManager: SimulationManager has no notify_npc_navigation_failed method")
|
||||
simulation_manager.notify_npc_navigation_failed(sim_id)
|
||||
|
||||
func _on_npc_died(npc: SimNPC) -> void:
|
||||
if not active_npc_visuals.has(npc.id):
|
||||
return
|
||||
|
||||
var visual = active_npc_visuals[npc.id]
|
||||
|
||||
if visual.has_method("apply_dead_visual_state"):
|
||||
visual.apply_dead_visual_state()
|
||||
else:
|
||||
push_error("WorldViewManager: NPCVisual has no apply_dead_visual_state method")
|
||||
push_error("WorldViewManager: NPCVisual has no apply_dead_visual_state")
|
||||
|
||||
Reference in New Issue
Block a user