212 lines
6.8 KiB
GDScript
212 lines
6.8 KiB
GDScript
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)
|