feat: generalize social memory and relationships
This commit is contained in:
@@ -2,7 +2,10 @@ class_name EventKnowledgeSystem
|
||||
extends RefCounted
|
||||
|
||||
const WITNESS_RADIUS := 10.0
|
||||
const MAX_RECENT_FACTS_PER_NPC := 3
|
||||
const MAX_RECENT_FACTS_PER_KNOWER := 3
|
||||
const MAX_RECENT_FACTS_PER_NPC := MAX_RECENT_FACTS_PER_KNOWER
|
||||
const MAX_PINNED_FACTS_PER_KNOWER := 4
|
||||
const COMMUNICATED_CONFIDENCE_FACTOR := 0.9
|
||||
|
||||
var known_events: Dictionary = {}
|
||||
|
||||
@@ -18,7 +21,16 @@ func observe_event(event: EconomicEventRecord, npcs: Array[SimNPC]) -> Array[Kno
|
||||
return learned
|
||||
var event_id := int(event.data["event_id"])
|
||||
var acquired_tick := int(event.data["tick"])
|
||||
if actor != null:
|
||||
if is_player_actor:
|
||||
var player_record := _remember(
|
||||
SimulationIds.PLAYER_ACTOR_ID,
|
||||
event_id,
|
||||
SimulationIds.KNOWLEDGE_ACQUISITION_PERFORMED,
|
||||
acquired_tick
|
||||
)
|
||||
if player_record != null:
|
||||
learned.append(player_record)
|
||||
elif actor != null:
|
||||
var actor_record := _remember(
|
||||
actor.id, event_id, SimulationIds.KNOWLEDGE_ACQUISITION_PERFORMED, acquired_tick
|
||||
)
|
||||
@@ -47,8 +59,11 @@ func communicate_event(
|
||||
) -> KnownEventStateRecord:
|
||||
if (
|
||||
event == null
|
||||
or not KnownEventStateRecord.is_valid_actor_id(speaker_id)
|
||||
or not KnownEventStateRecord.is_valid_actor_id(listener_id)
|
||||
or speaker_id == listener_id
|
||||
or listener_id == int(event.data["actor_id"])
|
||||
or acquired_tick < 0
|
||||
or not is_knowable_event(event)
|
||||
):
|
||||
return null
|
||||
@@ -70,10 +85,19 @@ func communicate_event(
|
||||
SimulationIds.KNOWLEDGE_ACQUISITION_COMMUNICATED,
|
||||
acquired_tick,
|
||||
speaker_id,
|
||||
speaker_record.get_acquisition_method()
|
||||
speaker_record.get_acquisition_method(),
|
||||
speaker_record.get_hop_count() + 1,
|
||||
speaker_record.get_confidence() * COMMUNICATED_CONFIDENCE_FACTOR,
|
||||
speaker_record.get_salience()
|
||||
)
|
||||
|
||||
|
||||
func communicate_event_to_player(
|
||||
event: EconomicEventRecord, speaker_id: int, acquired_tick: int
|
||||
) -> KnownEventStateRecord:
|
||||
return communicate_event(event, speaker_id, SimulationIds.PLAYER_ACTOR_ID, acquired_tick)
|
||||
|
||||
|
||||
func knows_event(knower_id: int, event_id: int) -> bool:
|
||||
return known_events.has(_key(knower_id, event_id))
|
||||
|
||||
@@ -82,6 +106,37 @@ func get_record(knower_id: int, event_id: int) -> KnownEventStateRecord:
|
||||
return known_events.get(_key(knower_id, event_id)) as KnownEventStateRecord
|
||||
|
||||
|
||||
func pin_event(knower_id: int, event_id: int, pinned: bool = true) -> bool:
|
||||
var record := get_record(knower_id, event_id)
|
||||
if record == null or record.is_pinned() == pinned:
|
||||
return false
|
||||
if pinned and _get_pinned_count(knower_id) >= MAX_PINNED_FACTS_PER_KNOWER:
|
||||
return false
|
||||
return record.set_pinned(pinned)
|
||||
|
||||
|
||||
func set_event_confidence(knower_id: int, event_id: int, confidence: float) -> bool:
|
||||
var record := get_record(knower_id, event_id)
|
||||
return record != null and record.set_confidence(confidence)
|
||||
|
||||
|
||||
func set_event_salience(knower_id: int, event_id: int, salience: float) -> bool:
|
||||
var record := get_record(knower_id, event_id)
|
||||
return record != null and record.set_salience(salience)
|
||||
|
||||
|
||||
func get_pinned_event_ids(knower_id: int) -> Array[int]:
|
||||
var records: Array[KnownEventStateRecord] = []
|
||||
for record in known_events.values():
|
||||
if record.get_knower_id() == knower_id and record.is_pinned():
|
||||
records.append(record)
|
||||
records.sort_custom(_sort_by_acquisition)
|
||||
var event_ids: Array[int] = []
|
||||
for record in records:
|
||||
event_ids.append(record.get_event_id())
|
||||
return event_ids
|
||||
|
||||
|
||||
func get_knowers(event_id: int) -> Array[int]:
|
||||
var knower_ids: Array[int] = []
|
||||
for record in known_events.values():
|
||||
@@ -146,6 +201,9 @@ func _get_ranked_event_ids(
|
||||
"event_id": record.get_event_id(),
|
||||
"acquired_tick": record.get_acquired_tick(),
|
||||
"lasting": record.get_event_id() in lasting_event_ids,
|
||||
"pinned": record.is_pinned(),
|
||||
"confidence": record.get_confidence(),
|
||||
"salience": record.get_salience(),
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -171,7 +229,7 @@ func maintain_retention(
|
||||
var recent_by_knower := {}
|
||||
for record in known_events.values():
|
||||
var key := _key(record.get_knower_id(), record.get_event_id())
|
||||
if lasting_keys.has(key):
|
||||
if lasting_keys.has(key) or record.is_pinned():
|
||||
continue
|
||||
if expire_by_age and current_tick - record.get_acquired_tick() >= max_recent_age:
|
||||
removal_keys[key] = true
|
||||
@@ -181,7 +239,7 @@ func maintain_retention(
|
||||
recent_by_knower[record.get_knower_id()] = recent
|
||||
for recent in recent_by_knower.values():
|
||||
recent.sort_custom(_sort_by_acquisition)
|
||||
var excess: int = recent.size() - MAX_RECENT_FACTS_PER_NPC
|
||||
var excess: int = recent.size() - MAX_RECENT_FACTS_PER_KNOWER
|
||||
for index in range(maxi(excess, 0)):
|
||||
var record := recent[index] as KnownEventStateRecord
|
||||
removal_keys[_key(record.get_knower_id(), record.get_event_id())] = true
|
||||
@@ -214,24 +272,46 @@ func _remember(
|
||||
event_id: int,
|
||||
acquisition_method: StringName,
|
||||
acquired_tick: int,
|
||||
source_npc_id: int = KnownEventStateRecord.NO_SOURCE_NPC_ID,
|
||||
source_acquisition_method: StringName = &""
|
||||
source_actor_id: int = KnownEventStateRecord.NO_SOURCE_ACTOR_ID,
|
||||
source_acquisition_method: StringName = &"",
|
||||
hop_count: int = KnownEventStateRecord.AUTO_HOP_COUNT,
|
||||
confidence: float = KnownEventStateRecord.DEFAULT_CONFIDENCE,
|
||||
salience: float = KnownEventStateRecord.DEFAULT_SALIENCE,
|
||||
pinned: bool = false
|
||||
) -> KnownEventStateRecord:
|
||||
if not KnownEventStateRecord.is_valid_actor_id(knower_id) or event_id < 0 or acquired_tick < 0:
|
||||
return null
|
||||
var key := _key(knower_id, event_id)
|
||||
if known_events.has(key):
|
||||
return null
|
||||
var source_npc_id := (
|
||||
source_actor_id if source_actor_id >= 0 else KnownEventStateRecord.NO_SOURCE_NPC_ID
|
||||
)
|
||||
var record := KnownEventStateRecord.create(
|
||||
knower_id,
|
||||
event_id,
|
||||
acquisition_method,
|
||||
source_npc_id,
|
||||
acquired_tick,
|
||||
source_acquisition_method
|
||||
source_acquisition_method,
|
||||
hop_count,
|
||||
confidence,
|
||||
salience,
|
||||
source_actor_id,
|
||||
pinned
|
||||
)
|
||||
known_events[key] = record
|
||||
return record
|
||||
|
||||
|
||||
func _get_pinned_count(knower_id: int) -> int:
|
||||
var count := 0
|
||||
for record in known_events.values():
|
||||
if record.get_knower_id() == knower_id and record.is_pinned():
|
||||
count += 1
|
||||
return count
|
||||
|
||||
|
||||
static func is_knowable_event(event: EconomicEventRecord) -> bool:
|
||||
if event == null:
|
||||
return false
|
||||
@@ -308,8 +388,14 @@ static func _sort_by_acquisition(
|
||||
|
||||
|
||||
static func _sort_by_importance(first: Dictionary, second: Dictionary) -> bool:
|
||||
if bool(first["pinned"]) != bool(second["pinned"]):
|
||||
return bool(first["pinned"])
|
||||
if bool(first["lasting"]) != bool(second["lasting"]):
|
||||
return bool(first["lasting"])
|
||||
if not is_equal_approx(float(first["salience"]), float(second["salience"])):
|
||||
return float(first["salience"]) > float(second["salience"])
|
||||
if not is_equal_approx(float(first["confidence"]), float(second["confidence"])):
|
||||
return float(first["confidence"]) > float(second["confidence"])
|
||||
if int(first["acquired_tick"]) != int(second["acquired_tick"]):
|
||||
return int(first["acquired_tick"]) > int(second["acquired_tick"])
|
||||
return int(first["event_id"]) > int(second["event_id"])
|
||||
|
||||
Reference in New Issue
Block a user