extends SceneTree const BERRY_ID := &"berry_bush_river_02" const TREE_ID := &"tree_river_resource_01" const CLUSTER_PATH := "JajceWorld/WorldObjects/ResourceClusters/RiverbankResourceCluster" var failures: Array[String] = [] func _initialize() -> void: call_deferred("_run") func _run() -> void: var main_scene: Node = load("res://main.tscn").instantiate() root.add_child(main_scene) await process_frame for _frame in 3: await physics_frame var manager = main_scene.get_node("SimulationManager") manager.set_process(false) var cluster := main_scene.get_node(CLUSTER_PATH) as RiverbankResourceCluster var berry := cluster.get_node("ResourceAnchors/BerryBush_River_02") as ResourceNode var tree := cluster.get_node("ResourceAnchors/Tree_River_Resource_01") as ResourceNode var berry_visual := berry.get_node("Visual/BerryPatchPresentation") as StylizedBerryPatch var tree_visual := tree.get_node("Visual/TreePresentation") as HarvestableTreePresentation _check_initial_presentation(berry_visual, tree_visual) var berry_state: ResourceStateRecord = manager.get_resource_state(BERRY_ID) var tree_state: ResourceStateRecord = manager.get_resource_state(TREE_ID) _check(berry_state != null and tree_state != null, "Authored resources should bind state") if berry_state == null or tree_state == null: _finish() return for _action in 2: _check( is_equal_approx(manager.harvest_resource_node(berry), berry.yield_per_action), "Player harvesting should extract the configured berry yield" ) var npc: SimNPC = manager.npcs[0] for _action in 2: _complete_npc_gather(manager, npc, tree) _check( is_equal_approx(berry_state.get_amount_remaining(), 2.0), "Two player harvests should leave the authored berry at 40 percent" ) _check( berry_visual.get_amount_tier() == ResourceAmountVisual.AmountTier.LOW, "The berry should derive its low tier from authoritative amount" ) _check( berry_visual.get_visible_leaf_count() == 3 and berry_visual.get_visible_berry_count() == 4, "The low berry should visibly thin to three leaves and four berries" ) _check( is_equal_approx(tree_state.get_amount_remaining(), 4.0), "Two NPC completions should leave the authored tree at half amount" ) _check( tree_visual.get_amount_tier() == ResourceAmountVisual.AmountTier.LOW, "The tree should derive its low tier from authoritative amount" ) _check( ( tree_visual.is_standing_visible() and not tree_visual.is_stump_visible() and tree_visual.get_visible_canopy_count() == 2 ), "The low tree should remain standing with a visibly thinned crown" ) _check( is_equal_approx(npc.get_inventory_amount(SimulationIds.RESOURCE_WOOD), 4.0), "The low tree state should come from real NPC inventory-producing extraction" ) var low_snapshot: String = manager.serialize_state() _check_no_visual_state(low_snapshot) while berry_state.can_extract(): manager.harvest_resource_node(berry) while tree_state.can_extract(): _complete_npc_gather(manager, npc, tree) _check_depleted_presentation(berry_visual, tree_visual) var depleted_snapshot: String = manager.serialize_state() _check_no_visual_state(depleted_snapshot) _check( manager.restore_state_from_json(low_snapshot), "Low authoritative resource state should restore" ) berry_state = manager.get_resource_state(BERRY_ID) tree_state = manager.get_resource_state(TREE_ID) _check( ( is_equal_approx(berry_state.get_amount_remaining(), 2.0) and berry_visual.get_visible_berry_count() == 4 and berry_visual.get_amount_tier() == ResourceAmountVisual.AmountTier.LOW ), "Restore should rebuild the low berry visual from amount alone" ) _check( ( is_equal_approx(tree_state.get_amount_remaining(), 4.0) and tree_visual.get_visible_canopy_count() == 2 and not tree_visual.is_stump_visible() ), "Restore should rebuild the low standing tree from amount alone" ) _check( manager.restore_state_from_json(depleted_snapshot), "Depleted authoritative resource state should restore" ) _check_depleted_presentation(berry_visual, tree_visual) _finish() func _check_initial_presentation( berry_visual: StylizedBerryPatch, tree_visual: HarvestableTreePresentation ) -> void: _check( ( berry_visual.get_amount_tier() == ResourceAmountVisual.AmountTier.FULL and berry_visual.get_visible_leaf_count() == 5 and berry_visual.get_visible_berry_count() == 8 ), "A full berry source should show all authored leaves and fruit" ) _check( ( tree_visual.get_amount_tier() == ResourceAmountVisual.AmountTier.FULL and tree_visual.is_standing_visible() and not tree_visual.is_stump_visible() and tree_visual.get_visible_canopy_count() == 4 ), "A full tree source should show its complete standing crown" ) func _complete_npc_gather(manager, npc: SimNPC, resource: ResourceNode) -> void: npc.target_id = resource.node_id var reserved: bool = manager.reserve_resource(resource.node_id, npc.id) _check(reserved, "NPC extraction should reserve the authored tree") if reserved: manager.call("_complete_resource_gather", npc, SimulationIds.ACTION_GATHER_WOOD) func _check_depleted_presentation( berry_visual: StylizedBerryPatch, tree_visual: HarvestableTreePresentation ) -> void: _check( ( berry_visual.get_amount_tier() == ResourceAmountVisual.AmountTier.DEPLETED and berry_visual.get_visible_leaf_count() == 2 and berry_visual.get_visible_berry_count() == 0 ), "Real player depletion should leave a small fruitless berry remnant" ) _check( ( tree_visual.get_amount_tier() == ResourceAmountVisual.AmountTier.DEPLETED and not tree_visual.is_standing_visible() and tree_visual.is_stump_visible() and tree_visual.get_visible_canopy_count() == 0 ), "Real NPC depletion should replace the standing tree with its stump" ) func _check_no_visual_state(snapshot: String) -> void: var parsed = JSON.parse_string(snapshot) _check(parsed is Dictionary, "Serialized simulation state should remain valid JSON") if not parsed is Dictionary: return var matched_records := 0 for resource_data in parsed.get("resources", []): if StringName(resource_data.get("node_id", "")) not in [BERRY_ID, TREE_ID]: continue matched_records += 1 for field in resource_data.keys(): var field_name := String(field) _check( ( not field_name.contains("visual") and not field_name.contains("visible") and not field_name.contains("tier") and not field_name.contains("stump") ), "Resource save fields should contain authority, never visual state" ) _check(matched_records == 2, "Both authored resources should remain in simulation saves") func _check(condition: bool, message: String) -> void: if not condition: failures.append(message) func _finish() -> void: if failures.is_empty(): print("[TEST] Jajce resource presentation passed: amount -> low/depleted -> restore") quit(0) return for failure in failures: push_error("[TEST] " + failure) quit(1)