175 lines
5.2 KiB
GDScript
175 lines
5.2 KiB
GDScript
class_name ActiveWorldAdapter
|
|
extends Node
|
|
|
|
const LoadedResourceSpatialIndexScript := preload(
|
|
"res://world/resource_nodes/LoadedResourceSpatialIndex.gd"
|
|
)
|
|
|
|
@export var pantry_storage: StorageNode
|
|
@export var woodpile_storage: StorageNode
|
|
@export_range(4.0, 128.0, 1.0) var resource_cell_size := 24.0
|
|
|
|
var _resource_index := LoadedResourceSpatialIndexScript.new()
|
|
|
|
|
|
func _ready() -> void:
|
|
_resource_index.configure(resource_cell_size)
|
|
add_to_group("active_world_adapter")
|
|
rebuild_resource_index()
|
|
|
|
|
|
func rebuild_resource_index() -> void:
|
|
_resource_index.clear()
|
|
for node in ResourceNode.get_all():
|
|
_resource_index.register_node(node, node.state)
|
|
|
|
|
|
func register_resource_node(node: ResourceNode, state: ResourceStateRecord = null) -> bool:
|
|
return _resource_index.register_node(node, state)
|
|
|
|
|
|
func unregister_resource_node(node_id: StringName) -> void:
|
|
_resource_index.unregister_node(node_id)
|
|
|
|
|
|
func get_resource_candidates(action_id: StringName) -> Array[Dictionary]:
|
|
return _resource_index.get_all_candidates(action_id)
|
|
|
|
|
|
func get_resource_candidates_in_radius(
|
|
action_id: StringName,
|
|
origin: Vector3,
|
|
max_distance: float,
|
|
min_distance_exclusive: float = -1.0
|
|
) -> Array[Dictionary]:
|
|
return _resource_index.get_candidates_in_radius(
|
|
action_id, origin, max_distance, min_distance_exclusive
|
|
)
|
|
|
|
|
|
func get_resource_query_profile(action_id: StringName, origin: Vector3) -> Dictionary:
|
|
return _resource_index.get_query_profile(action_id, origin)
|
|
|
|
|
|
func get_resource_nodes_in_radius(origin: Vector3, max_distance: float) -> Array[ResourceNode]:
|
|
return _resource_index.get_nodes_in_radius(origin, max_distance)
|
|
|
|
|
|
func get_resource_index_stats() -> Dictionary:
|
|
return _resource_index.get_stats()
|
|
|
|
|
|
func get_animal_candidates(action_id: StringName) -> Array[Dictionary]:
|
|
var candidates: Array[Dictionary] = []
|
|
for node in AnimalNode.get_all():
|
|
if not node.supports_action(action_id):
|
|
continue
|
|
(
|
|
candidates
|
|
. append(
|
|
{
|
|
"target_id": String(node.animal_id),
|
|
"position": node.get_interaction_position(),
|
|
"display_name": node.display_name,
|
|
}
|
|
)
|
|
)
|
|
candidates.sort_custom(
|
|
func(first: Dictionary, second: Dictionary) -> bool:
|
|
return String(first["target_id"]) < String(second["target_id"])
|
|
)
|
|
return candidates
|
|
|
|
|
|
func get_animal_routine_sites(species_id: StringName, animal_id: StringName) -> Array[Dictionary]:
|
|
var candidates: Array[Dictionary] = []
|
|
for site in AnimalRoutineSite.get_all():
|
|
if not site.supports_animal(animal_id, species_id):
|
|
continue
|
|
(
|
|
candidates
|
|
. append(
|
|
{
|
|
"site_id": String(site.site_id),
|
|
"position": site.get_routine_position(),
|
|
"display_name": site.display_name,
|
|
}
|
|
)
|
|
)
|
|
candidates.sort_custom(
|
|
func(first: Dictionary, second: Dictionary) -> bool:
|
|
return String(first["site_id"]) < String(second["site_id"])
|
|
)
|
|
return candidates
|
|
|
|
|
|
func get_animal_nodes_in_radius(origin: Vector3, max_distance: float) -> Array[AnimalNode]:
|
|
var nodes: Array[AnimalNode] = []
|
|
var maximum_distance_squared := maxf(max_distance, 0.0) * maxf(max_distance, 0.0)
|
|
for node in AnimalNode.get_all():
|
|
if origin.distance_squared_to(node.get_interaction_position()) <= maximum_distance_squared:
|
|
nodes.append(node)
|
|
nodes.sort_custom(
|
|
func(first: AnimalNode, second: AnimalNode) -> bool:
|
|
var first_distance := origin.distance_squared_to(first.get_interaction_position())
|
|
var second_distance := origin.distance_squared_to(second.get_interaction_position())
|
|
if not is_equal_approx(first_distance, second_distance):
|
|
return first_distance < second_distance
|
|
return String(first.animal_id) < String(second.animal_id)
|
|
)
|
|
return nodes
|
|
|
|
|
|
func get_activity_target(action_id: StringName, origin: Vector3 = Vector3.ZERO) -> Dictionary:
|
|
var best_candidate: Dictionary = {}
|
|
var best_distance := INF
|
|
for candidate in get_activity_candidates(action_id):
|
|
var position: Vector3 = candidate["position"]
|
|
var distance := origin.distance_squared_to(position)
|
|
if distance < best_distance:
|
|
best_distance = distance
|
|
best_candidate = candidate
|
|
if not best_candidate.is_empty():
|
|
return best_candidate
|
|
match action_id:
|
|
SimulationIds.ACTION_EAT:
|
|
return get_storage_target(SimulationIds.STORAGE_VILLAGE_PANTRY)
|
|
SimulationIds.ACTION_DEPOSIT_FOOD, SimulationIds.ACTION_WITHDRAW_FOOD:
|
|
return get_storage_target(SimulationIds.STORAGE_VILLAGE_PANTRY)
|
|
SimulationIds.ACTION_DEPOSIT_WOOD:
|
|
return get_storage_target(SimulationIds.STORAGE_VILLAGE_WOODPILE)
|
|
return {}
|
|
|
|
|
|
func get_activity_candidates(action_id: StringName) -> Array[Dictionary]:
|
|
var candidates: Array[Dictionary] = []
|
|
for candidate in ActivitySite.get_all():
|
|
var site := candidate as ActivitySite
|
|
if site == null:
|
|
continue
|
|
if not site.supports_action(action_id):
|
|
continue
|
|
candidates.append(
|
|
{
|
|
"target_id": String(site.site_id),
|
|
"position": site.get_interaction_position(),
|
|
"capacity": site.capacity
|
|
}
|
|
)
|
|
return candidates
|
|
|
|
|
|
func get_storage_target(storage_id: StringName) -> Dictionary:
|
|
var storage_node: StorageNode
|
|
match storage_id:
|
|
SimulationIds.STORAGE_VILLAGE_PANTRY:
|
|
storage_node = pantry_storage
|
|
SimulationIds.STORAGE_VILLAGE_WOODPILE:
|
|
storage_node = woodpile_storage
|
|
if storage_node == null:
|
|
return {}
|
|
return {
|
|
"target_id": String(storage_node.storage_id),
|
|
"position": storage_node.get_interaction_position()
|
|
}
|