class_name ActionTargetResolver extends RefCounted func resolve( npc: SimNPC, origin: Vector3, simulation_manager: Node, active_world_adapter: Node ) -> Dictionary: var definition := SimulationDefinitions.get_action(npc.current_task) if definition == null: return {} match definition.target_type: SimulationIds.TARGET_RESOURCE: return _resolve_resource( npc, origin, definition, simulation_manager, active_world_adapter ) SimulationIds.TARGET_ACTIVITY: return active_world_adapter.get_activity_target(npc.current_task) SimulationIds.TARGET_FREE: return { "target_id": "", "position": origin + simulation_manager.get_wander_offset(npc.id) } return {} func _resolve_resource( npc: SimNPC, origin: Vector3, definition: ActionDefinition, simulation_manager: Node, active_world_adapter: Node ) -> Dictionary: var best: Dictionary = {} var best_distance := INF for candidate in active_world_adapter.get_resource_candidates(definition.resource_action_id): var node_id := StringName(candidate["target_id"]) var state: ResourceStateRecord = simulation_manager.get_resource_state(node_id) if state == null or not state.can_npc_use() or not state.is_available_for(npc.id): continue var position: Vector3 = candidate["position"] var distance := origin.distance_squared_to(position) if distance < best_distance: best_distance = distance best = candidate if best.is_empty(): return {} var target_id := StringName(best["target_id"]) if not simulation_manager.reserve_resource(target_id, npc.id): return {} return best