Files
gamedev-the-steward/tests/unit/test_social_foundations.gd
2026-08-12 20:23:17 +02:00

201 lines
7.7 KiB
GDScript

extends GutTest
const EventKnowledgeSystemScript := preload("res://simulation/knowledge/EventKnowledgeSystem.gd")
const RelationshipSystemScript := preload("res://simulation/relationships/RelationshipSystem.gd")
func test_known_event_v3_migrates_metadata_and_player_is_a_valid_knower() -> void:
var legacy_data := {
"schema_version": KnownEventStateRecord.LEGACY_SCHEMA_VERSION,
"knower_id": 2,
"event_id": 12,
"acquisition_method": String(SimulationIds.KNOWLEDGE_ACQUISITION_COMMUNICATED),
"source_npc_id": 1,
"acquired_tick": 30,
"source_acquisition_method": String(SimulationIds.KNOWLEDGE_ACQUISITION_WITNESSED),
}
var migrated := KnownEventStateRecord.from_dictionary(legacy_data)
assert_not_null(migrated)
assert_eq(int(migrated.to_dictionary()["schema_version"]), KnownEventStateRecord.SCHEMA_VERSION)
assert_eq(migrated.get_source_actor_id(), 1)
assert_eq(migrated.get_hop_count(), 1)
assert_eq(migrated.get_confidence(), KnownEventStateRecord.DEFAULT_CONFIDENCE)
assert_eq(migrated.get_salience(), KnownEventStateRecord.DEFAULT_SALIENCE)
assert_false(migrated.is_pinned())
var player_record := KnownEventStateRecord.create(
SimulationIds.PLAYER_ACTOR_ID,
13,
SimulationIds.KNOWLEDGE_ACQUISITION_WITNESSED,
KnownEventStateRecord.NO_SOURCE_NPC_ID,
31
)
assert_not_null(KnownEventStateRecord.from_dictionary(player_record.to_dictionary()))
var invalid_knower_data := player_record.to_dictionary()
invalid_knower_data["knower_id"] = KnownEventStateRecord.NO_SOURCE_ACTOR_ID
assert_null(KnownEventStateRecord.from_dictionary(invalid_knower_data))
func test_direct_npc_knowledge_can_be_communicated_explicitly_to_player() -> void:
var event := EconomicEventRecord.create(
21,
SimulationIds.EVENT_STORAGE_DEPOSITED,
40,
0,
SimulationIds.npc_inventory_id(0),
SimulationIds.STORAGE_VILLAGE_PANTRY,
SimulationIds.RESOURCE_FOOD,
2.0,
Vector3.ZERO
)
var speaker_record := KnownEventStateRecord.create(
1,
int(event.data["event_id"]),
SimulationIds.KNOWLEDGE_ACQUISITION_WITNESSED,
KnownEventStateRecord.NO_SOURCE_NPC_ID,
40
)
var knowledge_system := EventKnowledgeSystemScript.new()
var records: Array[KnownEventStateRecord] = [speaker_record]
knowledge_system.restore(records)
assert_false(
knowledge_system.knows_event(SimulationIds.PLAYER_ACTOR_ID, int(event.data["event_id"]))
)
var communicated := knowledge_system.communicate_event_to_player(event, 1, 45)
assert_not_null(communicated)
assert_eq(communicated.get_knower_id(), SimulationIds.PLAYER_ACTOR_ID)
assert_eq(communicated.get_source_actor_id(), 1)
assert_eq(communicated.get_source_npc_id(), 1)
assert_eq(communicated.get_hop_count(), 1)
assert_true(is_equal_approx(communicated.get_confidence(), 0.9))
assert_eq(communicated.get_source_acquisition_method(), speaker_record.get_acquisition_method())
assert_null(knowledge_system.communicate_event(event, SimulationIds.PLAYER_ACTOR_ID, 2, 46))
func test_player_performed_world_event_is_known_without_a_witness() -> void:
var event := EconomicEventRecord.create(
22,
SimulationIds.EVENT_STORAGE_DEPOSITED,
41,
SimulationIds.PLAYER_ACTOR_ID,
SimulationIds.PLAYER_INVENTORY_ID,
SimulationIds.STORAGE_VILLAGE_PANTRY,
SimulationIds.RESOURCE_FOOD,
1.0,
Vector3(1000.0, 0.0, 1000.0)
)
var knowledge_system := EventKnowledgeSystemScript.new()
var learned := knowledge_system.observe_event(event, [])
assert_eq(learned.size(), 1)
assert_eq(learned[0].get_knower_id(), SimulationIds.PLAYER_ACTOR_ID)
assert_eq(learned[0].get_acquisition_method(), SimulationIds.KNOWLEDGE_ACQUISITION_PERFORMED)
func test_pinned_knowledge_is_bounded_and_survives_ordinary_retention() -> void:
var knowledge_system := EventKnowledgeSystemScript.new()
var records: Array[KnownEventStateRecord] = []
for event_id in range(1, 6):
records.append(
KnownEventStateRecord.create(
0,
event_id,
SimulationIds.KNOWLEDGE_ACQUISITION_WITNESSED,
KnownEventStateRecord.NO_SOURCE_NPC_ID,
event_id
)
)
knowledge_system.restore(records)
assert_true(knowledge_system.pin_event(0, 1))
var no_lasting: Array[KnownEventStateRecord] = []
var forgotten := knowledge_system.maintain_retention(5, 100, no_lasting, false)
assert_eq(forgotten.size(), 1)
assert_eq(forgotten[0].get_event_id(), 2)
assert_eq(knowledge_system.get_pinned_event_ids(0), [1])
assert_eq(knowledge_system.get_retained_event_ids(0, [], 0), [1, 5, 4, 3])
assert_true(knowledge_system.set_event_salience(0, 3, 2.0))
assert_eq(knowledge_system.get_record(0, 3).get_salience(), 1.0)
assert_true(knowledge_system.set_event_confidence(0, 3, -1.0))
assert_eq(knowledge_system.get_record(0, 3).get_confidence(), 0.0)
var pin_limit_system := EventKnowledgeSystemScript.new()
var pin_limit_records: Array[KnownEventStateRecord] = []
for event_id in range(1, 6):
pin_limit_records.append(KnownEventStateRecord.create(0, event_id))
pin_limit_system.restore(pin_limit_records)
for event_id in range(1, EventKnowledgeSystemScript.MAX_PINNED_FACTS_PER_KNOWER + 1):
assert_true(pin_limit_system.pin_event(0, event_id))
assert_false(
pin_limit_system.pin_event(0, EventKnowledgeSystemScript.MAX_PINNED_FACTS_PER_KNOWER + 1)
)
func test_relationship_v1_migrates_all_dimensions_and_exact_causes() -> void:
var legacy_data := {
"schema_version": RelationshipStateRecord.LEGACY_SCHEMA_VERSION,
"observer_id": 1,
"subject_id": 2,
"familiarity": 0.4,
"trust": 0.6,
"last_trust_cause_event_id": 8,
}
var relationship := RelationshipStateRecord.from_dictionary(legacy_data)
assert_not_null(relationship)
assert_eq(
int(relationship.to_dictionary()["schema_version"]), RelationshipStateRecord.SCHEMA_VERSION
)
assert_eq(relationship.get_affection(), 0.0)
assert_eq(relationship.get_respect(), 0.0)
assert_eq(relationship.get_fear(), 0.0)
assert_eq(relationship.get_obligation(), 0.0)
assert_eq(relationship.get_hostility(), 0.0)
assert_eq(relationship.get_last_trust_cause_event_id(), 8)
for index in range(RelationshipStateRecord.DIMENSIONS.size()):
var dimension: StringName = RelationshipStateRecord.DIMENSIONS[index]
var cause_event_id := 20 + index
assert_true(relationship.adjust_dimension(dimension, 0.1, cause_event_id) > 0.0)
assert_eq(relationship.get_last_cause_event_id(dimension), cause_event_id)
assert_true(relationship.adjust_hostility(2.0, 99) > 0.0)
assert_eq(relationship.get_hostility(), 1.0)
assert_eq(relationship.get_last_hostility_cause_event_id(), 99)
assert_not_null(RelationshipStateRecord.from_dictionary(relationship.to_dictionary()))
var player_observer := RelationshipStateRecord.create(SimulationIds.PLAYER_ACTOR_ID, 3, 0.2)
assert_not_null(RelationshipStateRecord.from_dictionary(player_observer.to_dictionary()))
func test_sparse_relationship_queries_are_deterministic_and_bounded() -> void:
var relationship_system := RelationshipSystemScript.new()
for subject_id in range(10):
var relationship := relationship_system.get_or_create_relationship(
SimulationIds.PLAYER_ACTOR_ID, subject_id, float(subject_id) / 10.0
)
assert_not_null(relationship)
assert_true(
(
relationship_system.adjust_relationship_dimension(
SimulationIds.PLAYER_ACTOR_ID, 0, RelationshipStateRecord.DIMENSION_RESPECT, 1.0, 77
)
> 0.0
)
)
var sorted := relationship_system.get_relationships_for_observer(SimulationIds.PLAYER_ACTOR_ID)
assert_eq(sorted.size(), 10)
assert_eq(sorted[0].get_subject_id(), 0)
assert_eq(sorted[9].get_subject_id(), 9)
var salient := relationship_system.get_salient_relationships(SimulationIds.PLAYER_ACTOR_ID, 100)
assert_eq(salient.size(), RelationshipSystemScript.MAX_BOUNDED_RELATIONSHIPS_PER_QUERY)
assert_eq(salient[0].get_subject_id(), 0)
assert_eq(
relationship_system.get_relationship_cause_event_id(
SimulationIds.PLAYER_ACTOR_ID, 0, RelationshipStateRecord.DIMENSION_RESPECT
),
77
)