extends RefCounted signal event_recorded(event: EconomicEventRecord) const DEFAULT_RATE_WINDOW_TICKS := 200 const DEFAULT_TICKS_PER_DAY := 200.0 var events: Array[EconomicEventRecord] = [] var next_event_id := 0 var world_events := WorldEventStore.new() var _events_by_id: Dictionary = {} var _event_ids_by_actor: Dictionary = {} var _event_ids_by_type: Dictionary = {} var _event_ids_by_tick: Dictionary = {} func record_economic( tick: int, event_type: StringName, actor_id: int, source_id: StringName, destination_id: StringName, item_id: StringName, amount: float, world_position: Vector3 = Vector3.ZERO ) -> EconomicEventRecord: if amount <= 0.0: return null var event := EconomicEventRecord.create( next_event_id, event_type, tick, actor_id, source_id, destination_id, item_id, amount, world_position ) _append(event) return event func record_narrative( tick: int, event_type: StringName, actor_id: int, source_id: StringName = &"", action_display: String = "", world_position: Vector3 = Vector3.ZERO, action_id: StringName = &"", item_id: StringName = &"", required_amount: float = 0.0 ) -> EconomicEventRecord: var event := EconomicEventRecord.create_narrative( next_event_id, event_type, tick, actor_id, source_id, action_display, world_position, action_id, item_id, required_amount ) _append(event) return event func get_for_actor(actor_id: int, max_count: int = 8) -> Array[EconomicEventRecord]: var results: Array[EconomicEventRecord] = [] var event_ids: Array = _event_ids_by_actor.get(actor_id, []) for index in range(event_ids.size() - 1, -1, -1): var event := get_by_id(int(event_ids[index])) if event == null: continue results.push_front(event) if results.size() >= max_count: break return results func get_recent(max_count: int = 5) -> Array[EconomicEventRecord]: var results: Array[EconomicEventRecord] = [] var start := maxi(events.size() - max_count, 0) for index in range(start, events.size()): results.append(events[index]) return results func get_by_id(event_id: int) -> EconomicEventRecord: return _events_by_id.get(event_id) as EconomicEventRecord func get_by_ids(event_ids: Array[int]) -> Array[EconomicEventRecord]: var results: Array[EconomicEventRecord] = [] for event_id in event_ids: var event := get_by_id(event_id) if event != null: results.append(event) return results func get_for_type(event_type: StringName, max_count: int = 0) -> Array[EconomicEventRecord]: var results: Array[EconomicEventRecord] = [] var event_ids: Array = _event_ids_by_type.get(event_type, []) var start := 0 if max_count <= 0 else maxi(event_ids.size() - max_count, 0) for index in range(start, event_ids.size()): var event := get_by_id(int(event_ids[index])) if event != null: results.append(event) return results func get_for_tick(tick: int) -> Array[EconomicEventRecord]: var results: Array[EconomicEventRecord] = [] for event_id in _event_ids_by_tick.get(tick, []): var event := get_by_id(int(event_id)) if event != null: results.append(event) return results func get_world_event(event_id: int) -> WorldEventRecord: return world_events.get_by_id(event_id) func get_consumption_rates( current_tick: int, window_ticks: int = DEFAULT_RATE_WINDOW_TICKS, ticks_per_day: float = DEFAULT_TICKS_PER_DAY ) -> Dictionary: var consumed := { SimulationIds.RESOURCE_FOOD: 0.0, SimulationIds.RESOURCE_WOOD: 0.0, } var first_tick := maxi(current_tick - window_ticks, 0) for event in get_for_type(SimulationIds.EVENT_ITEM_CONSUMED): if int(event.data["tick"]) < first_tick: continue var item_id := StringName(event.data["item_id"]) if consumed.has(item_id): consumed[item_id] = float(consumed[item_id]) + float(event.data["amount"]) var elapsed := maxi(current_tick - first_tick, 1) return { "food_per_day": float(consumed[SimulationIds.RESOURCE_FOOD]) / elapsed * ticks_per_day, "wood_per_day": float(consumed[SimulationIds.RESOURCE_WOOD]) / elapsed * ticks_per_day, } func restore(restored_events: Array[EconomicEventRecord], restored_next_id: int) -> void: events.clear() _events_by_id.clear() _event_ids_by_actor.clear() _event_ids_by_type.clear() _event_ids_by_tick.clear() world_events = WorldEventStore.new() for event in restored_events: _index(event) next_event_id = restored_next_id func _append(event: EconomicEventRecord) -> void: next_event_id += 1 _index(event) event_recorded.emit(event) func _index(event: EconomicEventRecord) -> void: if event == null: return var event_id := int(event.data["event_id"]) if _events_by_id.has(event_id): return events.append(event) _events_by_id[event_id] = event _append_index(_event_ids_by_actor, int(event.data["actor_id"]), event_id) _append_index(_event_ids_by_type, StringName(event.data["event_type"]), event_id) _append_index(_event_ids_by_tick, int(event.data["tick"]), event_id) world_events.append_economic(event, SimulationIds.WORLD_CORE, SimulationIds.LOCATION_JAJCE) static func _append_index(index: Dictionary, key: Variant, event_id: int) -> void: var event_ids: Array = index.get(key, []) event_ids.append(event_id) index[key] = event_ids