238 lines
6.7 KiB
GDScript
238 lines
6.7 KiB
GDScript
class_name KnownEventStateRecord
|
|
extends RefCounted
|
|
|
|
const SCHEMA_VERSION := 4
|
|
const LEGACY_SCHEMA_VERSION := 3
|
|
const NO_SOURCE_NPC_ID := -1
|
|
const NO_SOURCE_ACTOR_ID := -2
|
|
const DEFAULT_CONFIDENCE := 1.0
|
|
const DEFAULT_SALIENCE := 0.5
|
|
const AUTO_HOP_COUNT := -1
|
|
|
|
const VALID_ACQUISITION_METHODS := [
|
|
SimulationIds.KNOWLEDGE_ACQUISITION_PERFORMED,
|
|
SimulationIds.KNOWLEDGE_ACQUISITION_WITNESSED,
|
|
SimulationIds.KNOWLEDGE_ACQUISITION_COMMUNICATED,
|
|
SimulationIds.KNOWLEDGE_ACQUISITION_LEGACY,
|
|
]
|
|
const DIRECT_ACQUISITION_METHODS := [
|
|
SimulationIds.KNOWLEDGE_ACQUISITION_PERFORMED,
|
|
SimulationIds.KNOWLEDGE_ACQUISITION_WITNESSED,
|
|
]
|
|
|
|
var data: Dictionary
|
|
|
|
|
|
func _init(record_data: Dictionary = {}) -> void:
|
|
data = record_data.duplicate(true)
|
|
|
|
|
|
static func create(
|
|
knower_id: int,
|
|
event_id: int,
|
|
acquisition_method: StringName = SimulationIds.KNOWLEDGE_ACQUISITION_LEGACY,
|
|
source_npc_id: int = NO_SOURCE_NPC_ID,
|
|
acquired_tick: int = 0,
|
|
source_acquisition_method: StringName = &"",
|
|
hop_count: int = AUTO_HOP_COUNT,
|
|
confidence: float = DEFAULT_CONFIDENCE,
|
|
salience: float = DEFAULT_SALIENCE,
|
|
source_actor_id: int = NO_SOURCE_ACTOR_ID,
|
|
pinned: bool = false
|
|
) -> KnownEventStateRecord:
|
|
var is_communicated := acquisition_method == SimulationIds.KNOWLEDGE_ACQUISITION_COMMUNICATED
|
|
var canonical_source_actor_id := source_actor_id
|
|
var canonical_source_npc_id := source_npc_id
|
|
if is_communicated:
|
|
if canonical_source_actor_id == NO_SOURCE_ACTOR_ID:
|
|
canonical_source_actor_id = source_npc_id
|
|
canonical_source_npc_id = (
|
|
canonical_source_actor_id if canonical_source_actor_id >= 0 else NO_SOURCE_NPC_ID
|
|
)
|
|
else:
|
|
canonical_source_actor_id = NO_SOURCE_ACTOR_ID
|
|
canonical_source_npc_id = NO_SOURCE_NPC_ID
|
|
var canonical_hop_count := hop_count
|
|
if canonical_hop_count == AUTO_HOP_COUNT:
|
|
canonical_hop_count = 1 if is_communicated else 0
|
|
return (
|
|
KnownEventStateRecord
|
|
. new(
|
|
{
|
|
"schema_version": SCHEMA_VERSION,
|
|
"knower_id": knower_id,
|
|
"event_id": event_id,
|
|
"acquisition_method": String(acquisition_method),
|
|
"source_npc_id": canonical_source_npc_id,
|
|
"source_actor_id": canonical_source_actor_id,
|
|
"acquired_tick": acquired_tick,
|
|
"source_acquisition_method": String(source_acquisition_method),
|
|
"hop_count": canonical_hop_count,
|
|
"confidence": clampf(confidence, 0.0, 1.0),
|
|
"salience": clampf(salience, 0.0, 1.0),
|
|
"pinned": pinned,
|
|
}
|
|
)
|
|
)
|
|
|
|
|
|
static func from_dictionary(record_data: Dictionary) -> KnownEventStateRecord:
|
|
var version := int(record_data.get("schema_version", -1))
|
|
var normalized := record_data.duplicate(true)
|
|
if version == LEGACY_SCHEMA_VERSION:
|
|
normalized = _migrate_v3(record_data)
|
|
elif version != SCHEMA_VERSION:
|
|
return null
|
|
if not (
|
|
normalized
|
|
. has_all(
|
|
[
|
|
"knower_id",
|
|
"event_id",
|
|
"acquisition_method",
|
|
"source_npc_id",
|
|
"source_actor_id",
|
|
"acquired_tick",
|
|
"source_acquisition_method",
|
|
"hop_count",
|
|
"confidence",
|
|
"salience",
|
|
"pinned",
|
|
]
|
|
)
|
|
):
|
|
return null
|
|
var knower_id := int(normalized["knower_id"])
|
|
var event_id := int(normalized["event_id"])
|
|
var acquisition_method := StringName(normalized["acquisition_method"])
|
|
var source_npc_id := int(normalized["source_npc_id"])
|
|
var source_actor_id := int(normalized["source_actor_id"])
|
|
var acquired_tick := int(normalized["acquired_tick"])
|
|
var source_acquisition_method := StringName(normalized["source_acquisition_method"])
|
|
var hop_count := int(normalized["hop_count"])
|
|
var confidence := float(normalized["confidence"])
|
|
var salience := float(normalized["salience"])
|
|
if not is_valid_actor_id(knower_id) or event_id < 0 or acquired_tick < 0 or hop_count < 0:
|
|
return null
|
|
if not is_finite(confidence) or confidence < 0.0 or confidence > 1.0:
|
|
return null
|
|
if not is_finite(salience) or salience < 0.0 or salience > 1.0:
|
|
return null
|
|
if typeof(normalized["pinned"]) != TYPE_BOOL:
|
|
return null
|
|
if acquisition_method not in VALID_ACQUISITION_METHODS:
|
|
return null
|
|
if acquisition_method == SimulationIds.KNOWLEDGE_ACQUISITION_COMMUNICATED:
|
|
if not is_valid_actor_id(source_actor_id) or source_actor_id == knower_id:
|
|
return null
|
|
if source_actor_id >= 0 and source_npc_id != source_actor_id:
|
|
return null
|
|
if source_actor_id == SimulationIds.PLAYER_ACTOR_ID and source_npc_id != NO_SOURCE_NPC_ID:
|
|
return null
|
|
if source_acquisition_method not in DIRECT_ACQUISITION_METHODS or hop_count != 1:
|
|
return null
|
|
elif (
|
|
source_npc_id != NO_SOURCE_NPC_ID
|
|
or source_actor_id != NO_SOURCE_ACTOR_ID
|
|
or not source_acquisition_method.is_empty()
|
|
or hop_count != 0
|
|
):
|
|
return null
|
|
return KnownEventStateRecord.new(normalized)
|
|
|
|
|
|
func get_knower_id() -> int:
|
|
return int(data["knower_id"])
|
|
|
|
|
|
func get_event_id() -> int:
|
|
return int(data["event_id"])
|
|
|
|
|
|
func get_acquisition_method() -> StringName:
|
|
return StringName(data["acquisition_method"])
|
|
|
|
|
|
func get_source_npc_id() -> int:
|
|
return int(data["source_npc_id"])
|
|
|
|
|
|
func get_source_actor_id() -> int:
|
|
return int(data["source_actor_id"])
|
|
|
|
|
|
func get_acquired_tick() -> int:
|
|
return int(data["acquired_tick"])
|
|
|
|
|
|
func get_source_acquisition_method() -> StringName:
|
|
return StringName(data["source_acquisition_method"])
|
|
|
|
|
|
func get_hop_count() -> int:
|
|
return int(data["hop_count"])
|
|
|
|
|
|
func get_confidence() -> float:
|
|
return float(data["confidence"])
|
|
|
|
|
|
func get_salience() -> float:
|
|
return float(data["salience"])
|
|
|
|
|
|
func is_pinned() -> bool:
|
|
return bool(data["pinned"])
|
|
|
|
|
|
func set_pinned(pinned: bool) -> bool:
|
|
if is_pinned() == pinned:
|
|
return false
|
|
data["pinned"] = pinned
|
|
return true
|
|
|
|
|
|
func set_confidence(confidence: float) -> bool:
|
|
if not is_finite(confidence):
|
|
return false
|
|
var bounded := clampf(confidence, 0.0, 1.0)
|
|
if is_equal_approx(get_confidence(), bounded):
|
|
return false
|
|
data["confidence"] = bounded
|
|
return true
|
|
|
|
|
|
func set_salience(salience: float) -> bool:
|
|
if not is_finite(salience):
|
|
return false
|
|
var bounded := clampf(salience, 0.0, 1.0)
|
|
if is_equal_approx(get_salience(), bounded):
|
|
return false
|
|
data["salience"] = bounded
|
|
return true
|
|
|
|
|
|
func to_dictionary() -> Dictionary:
|
|
return data.duplicate(true)
|
|
|
|
|
|
static func is_valid_actor_id(actor_id: int) -> bool:
|
|
return actor_id >= 0 or actor_id == SimulationIds.PLAYER_ACTOR_ID
|
|
|
|
|
|
static func _migrate_v3(record_data: Dictionary) -> Dictionary:
|
|
var migrated := record_data.duplicate(true)
|
|
var acquisition_method := StringName(migrated.get("acquisition_method", &""))
|
|
var is_communicated := acquisition_method == SimulationIds.KNOWLEDGE_ACQUISITION_COMMUNICATED
|
|
migrated["schema_version"] = SCHEMA_VERSION
|
|
migrated["source_actor_id"] = (
|
|
int(migrated.get("source_npc_id", NO_SOURCE_NPC_ID))
|
|
if is_communicated
|
|
else NO_SOURCE_ACTOR_ID
|
|
)
|
|
migrated["hop_count"] = 1 if is_communicated else 0
|
|
migrated["confidence"] = DEFAULT_CONFIDENCE
|
|
migrated["salience"] = DEFAULT_SALIENCE
|
|
migrated["pinned"] = false
|
|
return migrated
|