feat: integrate regional caravan persistence
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
extends SceneTree
|
||||
|
||||
const DELIVERY_AMOUNT := 3.0
|
||||
|
||||
var failures: Array[String] = []
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_run")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
var uninterrupted := _create_manager(4242)
|
||||
var local_control := _create_manager(4242)
|
||||
_check(
|
||||
uninterrupted.request_regional_jajce_delivery(DELIVERY_AMOUNT, &"loaded"),
|
||||
"The production facade should dispatch the authored Travnik-to-Jajce delivery",
|
||||
)
|
||||
for step in 6:
|
||||
uninterrupted.simulate_tick()
|
||||
local_control.simulate_tick()
|
||||
var saved_manifest_json: String = uninterrupted.serialize_save_manifest()
|
||||
var saved_manifest := SimulationSaveManifest.from_json(saved_manifest_json)
|
||||
_check(saved_manifest != null, "A mid-route combined manifest should validate")
|
||||
|
||||
var restored := _create_manager(9999)
|
||||
_check(
|
||||
restored.restore_save_manifest(saved_manifest),
|
||||
"The local and regional authorities should restore from one manifest",
|
||||
)
|
||||
_check(
|
||||
restored.get_world_state_checksum() == uninterrupted.get_world_state_checksum(),
|
||||
"A mid-route restore should reproduce the complete authoritative checksum",
|
||||
)
|
||||
for step in RegionalSimulationFacade.ROUTE_TRAVEL_TICKS - 6:
|
||||
uninterrupted.simulate_tick()
|
||||
restored.simulate_tick()
|
||||
local_control.simulate_tick()
|
||||
|
||||
_check(
|
||||
restored.get_world_state_checksum() == uninterrupted.get_world_state_checksum(),
|
||||
"Restored regional travel should continue identically without a loaded caravan visual",
|
||||
)
|
||||
_assert_delivery_arrived(restored)
|
||||
_check(
|
||||
restored.get_state_checksum() == local_control.get_state_checksum(),
|
||||
"A regional delivery must not change the local simulation authority",
|
||||
)
|
||||
_check(
|
||||
_local_economy_snapshot(restored) == _local_economy_snapshot(local_control),
|
||||
"Regional trade goods must not mutate the local pantry, woodpile, or apothecary",
|
||||
)
|
||||
_assert_regional_events_stay_out_of_local_history(restored)
|
||||
|
||||
uninterrupted.free()
|
||||
restored.free()
|
||||
local_control.free()
|
||||
if failures.is_empty():
|
||||
print("[TEST] Production regional facade integration passed")
|
||||
quit(0)
|
||||
return
|
||||
for failure in failures:
|
||||
push_error("[TEST] " + failure)
|
||||
quit(1)
|
||||
|
||||
|
||||
func _create_manager(seed_value: int) -> Node:
|
||||
var manager: Node = load("res://simulation/SimulationManager.gd").new()
|
||||
manager.simulation_seed = seed_value
|
||||
manager.debug_logs = false
|
||||
root.add_child(manager)
|
||||
manager.set_process(false)
|
||||
return manager
|
||||
|
||||
|
||||
func _local_economy_snapshot(manager: Node) -> Dictionary:
|
||||
var apothecary: StorageStateRecord = manager.economy.get_storage(&"village_apothecary")
|
||||
return {
|
||||
"pantry": manager.get_pantry().to_dictionary(),
|
||||
"woodpile": manager.get_woodpile().to_dictionary(),
|
||||
"apothecary": apothecary.to_dictionary() if apothecary != null else {},
|
||||
}
|
||||
|
||||
|
||||
func _assert_delivery_arrived(manager: Node) -> void:
|
||||
var facade := RegionalSimulationFacade.from_dictionary(manager.get_regional_snapshot())
|
||||
_check(facade != null, "The production regional snapshot should remain valid")
|
||||
if facade == null:
|
||||
return
|
||||
var service := facade.get_service()
|
||||
var state := service.get_world_state()
|
||||
var caravan := state.get_mobile_group(SimulationIds.REGIONAL_CARAVAN_BLUE)
|
||||
_check(caravan != null and caravan.is_at_location(), "The caravan should finish at a location")
|
||||
if caravan != null:
|
||||
_check(
|
||||
caravan.get_current_location_id() == SimulationIds.REGIONAL_LOCATION_JAJCE,
|
||||
"The inbound caravan should finish in Jajce",
|
||||
)
|
||||
_check(
|
||||
caravan.get_cargo_amount(SimulationIds.RESOURCE_REGIONAL_TRADE_GOODS) == 0.0,
|
||||
"Arrival should empty the caravan's exact cargo ledger",
|
||||
)
|
||||
var jajce := state.get_settlement(SimulationIds.REGIONAL_SETTLEMENT_JAJCE)
|
||||
_check(
|
||||
(
|
||||
jajce != null
|
||||
and (
|
||||
jajce.get_stockpile_amount(SimulationIds.RESOURCE_REGIONAL_TRADE_GOODS)
|
||||
== DELIVERY_AMOUNT
|
||||
)
|
||||
),
|
||||
"Jajce's regional ledger should receive the exact delivered amount",
|
||||
)
|
||||
_check(
|
||||
service.get_event_store().size() == 4, "The regional causal chain should have four facts"
|
||||
)
|
||||
|
||||
|
||||
func _assert_regional_events_stay_out_of_local_history(manager: Node) -> void:
|
||||
var regional_types := [
|
||||
RegionalCaravanService.EVENT_CARGO_LOADED,
|
||||
RegionalCaravanService.EVENT_DEPARTED,
|
||||
RegionalCaravanService.EVENT_ARRIVED,
|
||||
RegionalCaravanService.EVENT_CARGO_DEPOSITED,
|
||||
]
|
||||
for event: EconomicEventRecord in manager.economic_events:
|
||||
_check(
|
||||
StringName(event.data.get("event_type", "")) not in regional_types,
|
||||
"Regional caravan facts must not enter the local numeric event-ID domain",
|
||||
)
|
||||
|
||||
|
||||
func _check(condition: bool, message: String) -> void:
|
||||
if not condition:
|
||||
failures.append(message)
|
||||
Reference in New Issue
Block a user