feat: add bounded npc memory retention
This commit is contained in:
@@ -17,6 +17,7 @@ signal npc_decision_recorded(npc: SimNPC, decision: ActionSelectionResult)
|
||||
signal relationship_changed(relationship: RelationshipStateRecord, cause_event: EconomicEventRecord)
|
||||
signal event_knowledge_changed(knower_id: int, event: EconomicEventRecord)
|
||||
signal event_knowledge_transferred(speaker_id: int, listener_id: int, event: EconomicEventRecord)
|
||||
signal event_knowledge_forgotten(knower_id: int, event: EconomicEventRecord)
|
||||
|
||||
var village := SimVillage.new()
|
||||
|
||||
@@ -158,6 +159,8 @@ func simulate_tick() -> void:
|
||||
|
||||
if village_was_changed:
|
||||
village_changed.emit(village)
|
||||
if tick_count % get_knowledge_review_interval() == 0:
|
||||
_maintain_event_knowledge(true)
|
||||
|
||||
if debug_logs:
|
||||
print(village.get_summary())
|
||||
@@ -600,13 +603,15 @@ func try_communicate_at_shared_activity(speaker_id: int, listener_id: int) -> bo
|
||||
var listener := _find_npc_by_id(listener_id)
|
||||
if not _can_communicate_at_shared_activity(speaker, listener):
|
||||
return false
|
||||
var known_event_ids := event_knowledge_system.get_known_event_ids(speaker.id, 0)
|
||||
for index in range(known_event_ids.size() - 1, -1, -1):
|
||||
var event := event_log.get_by_id(known_event_ids[index])
|
||||
var known_event_ids := event_knowledge_system.get_communicable_event_ids(
|
||||
speaker.id, _get_lasting_event_ids(speaker.id)
|
||||
)
|
||||
for event_id in known_event_ids:
|
||||
var event := event_log.get_by_id(event_id)
|
||||
if event == null:
|
||||
continue
|
||||
var learned_record := event_knowledge_system.communicate_event(
|
||||
event, speaker.id, listener.id
|
||||
event, speaker.id, listener.id, tick_count
|
||||
)
|
||||
if learned_record == null:
|
||||
continue
|
||||
@@ -648,13 +653,51 @@ func _can_communicate_at_shared_activity(speaker: SimNPC, listener: SimNPC) -> b
|
||||
func _apply_new_event_knowledge(
|
||||
known_event: KnownEventStateRecord, event: EconomicEventRecord
|
||||
) -> void:
|
||||
event_knowledge_changed.emit(known_event.get_knower_id(), event)
|
||||
var newly_informed_ids: Array[int] = [known_event.get_knower_id()]
|
||||
var changed_relationships: Array[RelationshipStateRecord] = relationship_system.apply_event(
|
||||
event, npcs, newly_informed_ids
|
||||
)
|
||||
event_knowledge_changed.emit(known_event.get_knower_id(), event)
|
||||
for relationship in changed_relationships:
|
||||
relationship_changed.emit(relationship, event)
|
||||
_maintain_event_knowledge(false)
|
||||
|
||||
|
||||
func _maintain_event_knowledge(expire_by_age: bool) -> void:
|
||||
var forgotten := event_knowledge_system.maintain_retention(
|
||||
tick_count, get_knowledge_review_interval(), _get_lasting_knowledge_records(), expire_by_age
|
||||
)
|
||||
for known_event in forgotten:
|
||||
var event := event_log.get_by_id(known_event.get_event_id())
|
||||
if event != null:
|
||||
event_knowledge_forgotten.emit(known_event.get_knower_id(), event)
|
||||
|
||||
|
||||
func _get_lasting_knowledge_records() -> Array[KnownEventStateRecord]:
|
||||
var lasting: Array[KnownEventStateRecord] = []
|
||||
var seen := {}
|
||||
for relationship in relationship_system.get_all_sorted():
|
||||
var event_id := relationship.get_last_trust_cause_event_id()
|
||||
if event_id == RelationshipStateRecord.NO_CAUSE_EVENT:
|
||||
continue
|
||||
var record := event_knowledge_system.get_record(relationship.get_observer_id(), event_id)
|
||||
if record == null:
|
||||
continue
|
||||
var key := "%d:%d" % [record.get_knower_id(), record.get_event_id()]
|
||||
if seen.has(key):
|
||||
continue
|
||||
seen[key] = true
|
||||
lasting.append(record)
|
||||
return lasting
|
||||
|
||||
|
||||
func _get_lasting_event_ids(npc_id: int) -> Array[int]:
|
||||
var event_ids: Array[int] = []
|
||||
for record in _get_lasting_knowledge_records():
|
||||
if record.get_knower_id() == npc_id:
|
||||
event_ids.append(record.get_event_id())
|
||||
event_ids.sort()
|
||||
return event_ids
|
||||
|
||||
|
||||
func _find_npc_by_id(npc_id: int) -> SimNPC:
|
||||
@@ -695,6 +738,24 @@ func get_known_event_record(npc_id: int, event_id: int) -> KnownEventStateRecord
|
||||
return event_knowledge_system.get_record(npc_id, event_id)
|
||||
|
||||
|
||||
func is_known_event_lasting(npc_id: int, event_id: int) -> bool:
|
||||
return event_id in _get_lasting_event_ids(npc_id)
|
||||
|
||||
|
||||
func get_memory_summary(npc_id: int) -> Dictionary:
|
||||
var total := event_knowledge_system.get_known_event_ids(npc_id, 0).size()
|
||||
var lasting := _get_lasting_event_ids(npc_id).size()
|
||||
return {"lasting": lasting, "recent": maxi(total - lasting, 0)}
|
||||
|
||||
|
||||
func get_knowledge_review_interval() -> int:
|
||||
var active_cycle_duration := (
|
||||
clock.cycle_duration_seconds if clock != null else cycle_duration_seconds
|
||||
)
|
||||
var active_tick_interval := clock.tick_interval if clock != null else tick_interval
|
||||
return maxi(roundi(active_cycle_duration / maxf(active_tick_interval, 0.0001)), 1)
|
||||
|
||||
|
||||
func get_current_speed() -> String:
|
||||
return "%.2fx" % SPEED_LEVELS[speed_index]
|
||||
|
||||
@@ -1018,6 +1079,7 @@ func restore_state(record: SimulationStateRecord) -> bool:
|
||||
npcs.append(npc_record.restore(debug_logs))
|
||||
relationship_system.restore(record.relationships)
|
||||
event_knowledge_system.restore(record.event_knowledge)
|
||||
_maintain_event_knowledge(tick_count % get_knowledge_review_interval() == 0)
|
||||
|
||||
wander_random_sources.clear()
|
||||
var wander_streams: Array = record.simulation["wander_random_streams"]
|
||||
|
||||
Reference in New Issue
Block a user