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 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] = [] for index in range(events.size() - 1, -1, -1): var event := events[index] if int(event.data["actor_id"]) != actor_id: continue results.append(event) if results.size() >= max_count: break results.reverse() 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: for event in events: if int(event.data["event_id"]) == event_id: return event return null 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 events: if int(event.data["tick"]) < first_tick: continue if StringName(event.data["event_type"]) != SimulationIds.EVENT_ITEM_CONSUMED: 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 = restored_events.duplicate() next_event_id = restored_next_id func _append(event: EconomicEventRecord) -> void: next_event_id += 1 events.append(event) event_recorded.emit(event)