class_name EventKnowledgeSystem extends RefCounted const WITNESS_RADIUS := 10.0 var known_events: Dictionary = {} func observe_event(event: EconomicEventRecord, npcs: Array[SimNPC]) -> Array[KnownEventStateRecord]: var learned: Array[KnownEventStateRecord] = [] if not _is_witnessable(event): return learned var actor := _find_npc(int(event.data["actor_id"]), npcs) if actor == null: return learned var actor_record := _remember(actor.id, int(event.data["event_id"])) if actor_record != null: learned.append(actor_record) var witness_radius_squared := WITNESS_RADIUS * WITNESS_RADIUS var event_position := event.get_world_position() for npc in npcs: if npc.id == actor.id or npc.is_dead: continue if npc.position.distance_squared_to(event_position) > witness_radius_squared: continue var witness_record := _remember(npc.id, int(event.data["event_id"])) if witness_record != null: learned.append(witness_record) learned.sort_custom(_sort_records) return learned func knows_event(knower_id: int, event_id: int) -> bool: return known_events.has(_key(knower_id, event_id)) func get_knowers(event_id: int) -> Array[int]: var knower_ids: Array[int] = [] for record in known_events.values(): if record.get_event_id() == event_id: knower_ids.append(record.get_knower_id()) knower_ids.sort() return knower_ids func get_known_event_ids(knower_id: int, max_count: int = 3) -> Array[int]: var event_ids: Array[int] = [] for record in known_events.values(): if record.get_knower_id() == knower_id: event_ids.append(record.get_event_id()) event_ids.sort() if max_count <= 0 or event_ids.size() <= max_count: return event_ids var recent_ids: Array[int] = [] for index in range(event_ids.size() - max_count, event_ids.size()): recent_ids.append(event_ids[index]) return recent_ids func get_all_sorted() -> Array[KnownEventStateRecord]: var records: Array[KnownEventStateRecord] = [] for record in known_events.values(): records.append(record) records.sort_custom(_sort_records) return records func restore(records: Array[KnownEventStateRecord]) -> void: known_events.clear() for record in records: known_events[_key(record.get_knower_id(), record.get_event_id())] = record func _remember(knower_id: int, event_id: int) -> KnownEventStateRecord: var key := _key(knower_id, event_id) if known_events.has(key): return null var record := KnownEventStateRecord.create(knower_id, event_id) known_events[key] = record return record func _is_witnessable(event: EconomicEventRecord) -> bool: return ( StringName(event.data["event_type"]) == SimulationIds.EVENT_STORAGE_DEPOSITED and StringName(event.data["item_id"]) == SimulationIds.RESOURCE_FOOD and float(event.data["amount"]) > 0.0 ) static func _find_npc(npc_id: int, npcs: Array[SimNPC]) -> SimNPC: for npc in npcs: if npc.id == npc_id: return npc return null static func _key(knower_id: int, event_id: int) -> String: return "%d:%d" % [knower_id, event_id] static func _sort_records(first: KnownEventStateRecord, second: KnownEventStateRecord) -> bool: if first.get_knower_id() != second.get_knower_id(): return first.get_knower_id() < second.get_knower_id() return first.get_event_id() < second.get_event_id()