perf: index simulation event history
This commit is contained in:
@@ -7,6 +7,12 @@ 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(
|
||||
@@ -65,14 +71,14 @@ func record_narrative(
|
||||
|
||||
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:
|
||||
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.append(event)
|
||||
results.push_front(event)
|
||||
if results.size() >= max_count:
|
||||
break
|
||||
results.reverse()
|
||||
return results
|
||||
|
||||
|
||||
@@ -85,10 +91,7 @@ func get_recent(max_count: int = 5) -> Array[EconomicEventRecord]:
|
||||
|
||||
|
||||
func get_by_id(event_id: int) -> EconomicEventRecord:
|
||||
for event in events:
|
||||
if int(event.data["event_id"]) == event_id:
|
||||
return event
|
||||
return null
|
||||
return _events_by_id.get(event_id) as EconomicEventRecord
|
||||
|
||||
|
||||
func get_by_ids(event_ids: Array[int]) -> Array[EconomicEventRecord]:
|
||||
@@ -100,6 +103,30 @@ func get_by_ids(event_ids: Array[int]) -> Array[EconomicEventRecord]:
|
||||
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,
|
||||
@@ -110,11 +137,9 @@ func get_consumption_rates(
|
||||
SimulationIds.RESOURCE_WOOD: 0.0,
|
||||
}
|
||||
var first_tick := maxi(current_tick - window_ticks, 0)
|
||||
for event in events:
|
||||
for event in get_for_type(SimulationIds.EVENT_ITEM_CONSUMED):
|
||||
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"])
|
||||
@@ -126,11 +151,38 @@ func get_consumption_rates(
|
||||
|
||||
|
||||
func restore(restored_events: Array[EconomicEventRecord], restored_next_id: int) -> void:
|
||||
events = restored_events.duplicate()
|
||||
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
|
||||
events.append(event)
|
||||
_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
|
||||
|
||||
@@ -147,6 +147,10 @@ func test_event_log_preserves_order_and_derives_consumption_rate() -> void:
|
||||
assert_eq(int(event_log.events[0].data["event_id"]), 0)
|
||||
assert_eq(int(event_log.events[1].data["event_id"]), 1)
|
||||
assert_eq(event_log.get_for_actor(4).size(), 2)
|
||||
assert_eq(event_log.get_by_id(1), event_log.events[1])
|
||||
assert_eq(event_log.get_for_type(SimulationIds.EVENT_ITEM_CONSUMED), [event_log.events[1]])
|
||||
assert_eq(event_log.get_for_tick(20), [event_log.events[1]])
|
||||
assert_eq(event_log.get_world_event(1).get_event_type(), SimulationIds.EVENT_ITEM_CONSUMED)
|
||||
assert_eq(float(event_log.get_consumption_rates(200)["food_per_day"]), 1.0)
|
||||
var legacy_event_data := event_log.events[1].to_dictionary()
|
||||
legacy_event_data["schema_version"] = EconomicEventRecord.LEGACY_SCHEMA_VERSION
|
||||
@@ -155,6 +159,13 @@ func test_event_log_preserves_order_and_derives_consumption_rate() -> void:
|
||||
assert_not_null(migrated_event)
|
||||
assert_eq(migrated_event.get_world_position(), Vector3.ZERO)
|
||||
|
||||
var restored_log := SimulationEventLogScript.new()
|
||||
restored_log.restore(event_log.events, event_log.next_event_id)
|
||||
assert_eq(restored_log.get_by_id(0), event_log.events[0])
|
||||
assert_eq(restored_log.get_for_actor(4).size(), 2)
|
||||
assert_eq(restored_log.get_for_type(SimulationIds.EVENT_TASK_STARTED).size(), 1)
|
||||
assert_eq(restored_log.get_world_event(1).get_event_id(), 1)
|
||||
|
||||
|
||||
func test_food_aid_builds_directed_trust_once_per_event() -> void:
|
||||
var contributor := SimNPC.new(0, "Amina", SimulationIds.PROFESSION_FARMER, 5.0, 5.0)
|
||||
|
||||
Reference in New Issue
Block a user