extends SceneTree var failures: Array[String] = [] func _initialize() -> void: call_deferred("_run") func _run() -> void: var manager := _create_manager(913) manager.set_process(false) var pantry: StorageStateRecord = manager.get_pantry() pantry.withdraw(SimulationIds.RESOURCE_FOOD, pantry.get_amount(SimulationIds.RESOURCE_FOOD)) pantry.deposit(SimulationIds.RESOURCE_FOOD, 2.0) manager.economy.sync_resource(SimulationIds.RESOURCE_FOOD) var berry := ResourceNode.new() berry.name = "CitizenBerry" berry.node_id = &"citizen_berry" berry.action_id = SimulationIds.ACTION_GATHER_FOOD berry.resource_id = SimulationIds.RESOURCE_FOOD berry.initial_amount = 2.0 berry.yield_per_action = 1.0 berry.debug_label_enabled = false var interaction_point := Marker3D.new() interaction_point.name = "InteractionPoint" interaction_point.position = Vector3.ZERO berry.add_child(interaction_point) root.add_child(berry) await process_frame _check( manager.register_resource_node(berry), "Player citizen test should bind a real finite ResourceNode" ) var initial_hunger: float = manager.get_player_state().get_hunger() manager.simulate_tick() _check( is_equal_approx(manager.get_player_state().get_hunger(), initial_hunger + 0.125), "Player hunger should advance deterministically on each simulation tick" ) _check( is_equal_approx(manager.get_player_state().get_energy(), 100.0 - 0.0625), "Player energy should drain by an exact binary fraction each tick" ) _check( is_equal_approx(manager.harvest_resource_node(berry), 1.0), "The player should carry the first finite yield" ) _check( is_equal_approx(manager.harvest_resource_node(berry), 1.0), "The player should carry the second finite yield" ) _check( is_equal_approx( manager.get_player_state().get_inventory_amount(SimulationIds.RESOURCE_FOOD), 2.0 ), "Carried player food should be conserved across harvests" ) var food_before: float = manager.get_player_state().get_hunger() _check(manager.eat_player_food(), "The player should eat carried food") _check( ( is_equal_approx(manager.get_player_state().get_hunger(), maxf(food_before - 55.0, 0.0)) and is_equal_approx( manager.get_player_state().get_inventory_amount(SimulationIds.RESOURCE_FOOD), 1.0 ) ), "Eating carried food should ease hunger and consume exactly one unit" ) _check( is_equal_approx(manager.deposit_player_inventory(SimulationIds.RESOURCE_FOOD), 1.0), "The player should deposit the remaining carried food" ) _check( ( is_equal_approx( manager.get_player_state().get_inventory_amount(SimulationIds.RESOURCE_FOOD), 0.0 ) and is_equal_approx(pantry.get_amount(SimulationIds.RESOURCE_FOOD), 3.0) ), "Deposit should move carried food into the pantry without creating or destroying it" ) var food_before_pantry: float = pantry.get_amount(SimulationIds.RESOURCE_FOOD) var hunger_before: float = manager.get_player_state().get_hunger() _check(manager.eat_player_food(), "The player should eat from the pantry when carrying nothing") _check( ( is_equal_approx( pantry.get_amount(SimulationIds.RESOURCE_FOOD), food_before_pantry - 1.0 ) and is_equal_approx( manager.get_player_state().get_hunger(), maxf(hunger_before - 55.0, 0.0) ) ), "Pantry eating should consume one village food and ease player hunger" ) manager.simulate_tick() var mid_hunger: float = manager.get_player_state().get_hunger() var saved_json: String = manager.serialize_state() var restored := _create_manager(914) _check( restored.restore_state_from_json(saved_json), "Player state should survive schema-v13 save and restore" ) _check( ( restored.get_state_checksum() == manager.get_state_checksum() and is_equal_approx(restored.get_player_state().get_hunger(), mid_hunger) ), "Restore should preserve the deterministic player needs and checksum" ) restored.free() var v12_data: Dictionary = manager.create_state_record().to_dictionary() v12_data["schema_version"] = SimulationStateRecord.PLAYER_NEEDS_SCHEMA_VERSION v12_data.erase("player") var migrated := SimulationStateRecord.from_dictionary(v12_data) _check( ( migrated != null and migrated.player != null and is_equal_approx(migrated.player.get_hunger(), 40.0) and is_equal_approx(migrated.player.get_energy(), 100.0) and migrated.player.get_carried_total() == 0.0 ), "World schema v12 should migrate to v13 with a fresh default player record" ) berry.queue_free() manager.free() _finish() func _create_manager(seed_value: int = 913) -> Node: var manager: Node = load("res://simulation/SimulationManager.gd").new() manager.simulation_seed = seed_value manager.debug_logs = false var home_positions: Array[Vector3] = [ Vector3(0.0, 0.0, 0.0), Vector3(2.0, 0.0, 0.0), Vector3(10.0, 0.0, 0.0), Vector3(12.0, 0.0, 0.0), Vector3(30.0, 0.0, 30.0), Vector3(40.0, 0.0, 40.0), ] manager.home_positions = home_positions root.add_child(manager) manager.set_process(false) return manager func _finish() -> void: if failures.is_empty(): print("[TEST] Player citizen loop passed: needs -> carry -> eat -> deposit") quit(0) return for failure in failures: push_error("[TEST] " + failure) quit(1) func _check(condition: bool, message: String) -> void: if not condition: failures.append(message)