fix: preserve deterministic decisions across saves

This commit is contained in:
Rijad Zuzo
2026-08-12 20:30:21 +02:00
parent ed7236257a
commit 6851e15f77
5 changed files with 38 additions and 10 deletions
+15 -9
View File
@@ -27,7 +27,7 @@ func update_modifiers() -> void:
food_modifier = 2.0 food_modifier = 2.0
if wood <= 0: if wood <= 0:
wood_modifier = 2.0 wood_modifier = 2.0
if safety < 20: if _strictly_below(safety, 20.0):
safety_modifier = 2.0 safety_modifier = 2.0
if knowledge > 25: if knowledge > 25:
knowledge_modifier = 0.75 knowledge_modifier = 0.75
@@ -46,24 +46,24 @@ func update_priorities() -> void:
safety_priority = 1.0 safety_priority = 1.0
knowledge_priority = 1.0 knowledge_priority = 1.0
if food < 10.0: if _strictly_below(food, 10.0):
food_priority = 3.0 food_priority = 3.0
elif food < 20.0: elif _strictly_below(food, 20.0):
food_priority = 2.0 food_priority = 2.0
if wood < 5.0: if _strictly_below(wood, 5.0):
wood_priority = 2.5 wood_priority = 2.5
elif wood < 15.0: elif _strictly_below(wood, 15.0):
wood_priority = 1.75 wood_priority = 1.75
if safety < 25.0: if _strictly_below(safety, 25.0):
safety_priority = 3.0 safety_priority = 3.0
elif safety < 50.0: elif _strictly_below(safety, 50.0):
safety_priority = 1.5 safety_priority = 1.5
if knowledge < 5.0: if _strictly_below(knowledge, 5.0):
knowledge_priority = 1.75 knowledge_priority = 1.75
elif knowledge < 15.0: elif _strictly_below(knowledge, 15.0):
knowledge_priority = 1.25 knowledge_priority = 1.25
if debug_logs: if debug_logs:
@@ -147,3 +147,9 @@ func get_priority_summary() -> String:
func debug_log(message: String) -> void: func debug_log(message: String) -> void:
if debug_logs: if debug_logs:
print("[Village] ", message) print("[Village] ", message)
static func _strictly_below(value: float, threshold: float) -> bool:
# JSON round trips can normalize a value a few ULPs below a threshold to the
# exact decimal. Treat that boundary identically before and after saving.
return value < threshold and not is_equal_approx(value, threshold)
+4
View File
@@ -1359,6 +1359,10 @@ func restore_state(record: SimulationStateRecord) -> bool:
village = record.village.restore(debug_logs) village = record.village.restore(debug_logs)
economy.configure(village, debug_logs) economy.configure(village, debug_logs)
economy.restore_storage(record.storages) economy.restore_storage(record.storages)
# Priorities and modifiers are deterministic derived state, not save payload.
# Rebuild them before the next decision so save/load cannot change outcomes.
village.update_modifiers()
village.update_priorities()
event_log.restore(record.economic_events, int(record.simulation["next_event_id"])) event_log.restore(record.economic_events, int(record.simulation["next_event_id"]))
latest_decisions.clear() latest_decisions.clear()
npcs.clear() npcs.clear()
+13 -1
View File
@@ -138,7 +138,19 @@ static func from_dictionary(record_data: Dictionary) -> KnownEventStateRecord:
or hop_count != 0 or hop_count != 0
): ):
return null return null
return KnownEventStateRecord.new(normalized) return create(
knower_id,
event_id,
acquisition_method,
source_npc_id,
acquired_tick,
source_acquisition_method,
hop_count,
confidence,
salience,
source_actor_id,
bool(normalized["pinned"])
)
func get_knower_id() -> int: func get_knower_id() -> int:
@@ -89,6 +89,11 @@ static func from_dictionary(record_data: Dictionary) -> RelationshipStateRecord:
return null return null
if cause_event_id < NO_CAUSE_EVENT: if cause_event_id < NO_CAUSE_EVENT:
return null return null
normalized[String(dimension)] = value
normalized[_cause_key(dimension)] = cause_event_id
normalized["schema_version"] = SCHEMA_VERSION
normalized["observer_id"] = observer_id
normalized["subject_id"] = subject_id
return RelationshipStateRecord.new(normalized) return RelationshipStateRecord.new(normalized)
@@ -0,0 +1 @@
uid://becxio7ec31yj