extends SceneTree ## Smoke test verifying chunk coordinate mapping and streaming behavior. ## Regression test for the issue where moving forward in Z unloaded chunk (0,0,0) ## because of transposed Godot Y (Height) and Godot Z (Ground) in coord_for_position. var passed := 0 var failed := 0 func _check(label: String, cond: bool) -> void: if cond: passed += 1 print(" PASS: ", label) else: failed += 1 printerr(" FAIL: ", label) func _init() -> void: _test_coord_for_position() _test_chunk_stream_manager_proximity() print("\n=== SMOKE RESULT: %d/%d passed ===" % [passed, passed + failed]) quit(0 if failed == 0 else 1) func _test_coord_for_position() -> void: print("--- Chunk.coord_for_position coordinate mapping ---") # In Godot 3D: X is East/West (chunk X), Y is Height/Up (chunk Z), Z is North/South (chunk Y). # Spawn origin var c0 := Chunk.coord_for_position(Vector3(0.0, 1.5, 0.0)) _check("Origin at (0, 1.5, 0) maps to (0, 0, 0)", c0 == Vector3i(0, 0, 0)) # Moving along Godot Z (North/South) within chunk 0: # Previously at Z=3, coord.z was incorrectly 3, which exceeded streaming_radius and unloaded chunk 0! var c3 := Chunk.coord_for_position(Vector3(0.0, 1.5, 3.0)) _check("Walking 3m forward to Z=3 maps to chunk (0, 0, 0)", c3 == Vector3i(0, 0, 0)) var c20 := Chunk.coord_for_position(Vector3(10.0, 1.5, 20.0)) _check("Inside chunk at (10, 1.5, 20) maps to (0, 0, 0)", c20 == Vector3i(0, 0, 0)) var c31 := Chunk.coord_for_position(Vector3(31.0, 1.5, 31.0)) _check("Far corner of chunk at (31, 1.5, 31) maps to (0, 0, 0)", c31 == Vector3i(0, 0, 0)) # Crossing into adjacent chunks var cz_next := Chunk.coord_for_position(Vector3(0.0, 1.5, 32.0)) _check("Crossing Z=32 maps to chunk Y=1 (0, 1, 0)", cz_next == Vector3i(0, 1, 0)) var cx_next := Chunk.coord_for_position(Vector3(32.0, 1.5, 0.0)) _check("Crossing X=32 maps to chunk X=1 (1, 0, 0)", cx_next == Vector3i(1, 0, 0)) var cz_prev := Chunk.coord_for_position(Vector3(0.0, 1.5, -1.0)) _check("Negative Z maps to chunk Y=-1 (0, -1, 0)", cz_prev == Vector3i(0, -1, 0)) var cx_prev := Chunk.coord_for_position(Vector3(-1.0, 1.5, 0.0)) _check("Negative X maps to chunk X=-1 (-1, 0, 0)", cx_prev == Vector3i(-1, 0, 0)) # Player height / jumping: var c_jump := Chunk.coord_for_position(Vector3(0.0, 5.0, 0.0)) _check("Jumping to height Y=5 in flat world stays at cz=0", c_jump == Vector3i(0, 0, 0)) func _test_chunk_stream_manager_proximity() -> void: print("--- ChunkStreamManager streaming proximity ---") var sm := ChunkStreamManager.new() sm.streaming_radius = 2 var player := Node3D.new() player.position = Vector3(0.0, 1.5, 0.0) root.add_child(player) root.add_child(sm) sm.player = player sm.is_active = true # Simulate immediate streaming update on spawn sm._update_streaming() var targets: Dictionary = sm._compute_target_chunks() _check("Target chunks computed on spawn", targets.size() > 0) _check("Spawn chunk (0,0,0) is in target set", targets.has(Vector3i(0, 0, 0))) # Ensure flat world doesn't spam non-zero cz chunks var all_cz_zero := true for coord in targets.keys(): if coord.z != 0: all_cz_zero = false break _check("Flat world targets only contain cz=0", all_cz_zero) # Simulate moving close to placed lampposts (Z = 1, 2, 3, 4, 5, 10, 20) player.position = Vector3(0.0, 1.5, 3.0) sm._update_streaming() targets = sm._compute_target_chunks() _check("Approaching lamppost at Z=3: chunk (0,0,0) is STILL in target set", targets.has(Vector3i(0, 0, 0))) player.position = Vector3(5.0, 1.5, 15.0) sm._update_streaming() targets = sm._compute_target_chunks() _check("Approaching lamppost at Z=15: chunk (0,0,0) is STILL in target set", targets.has(Vector3i(0, 0, 0))) player.position = Vector3(0.0, 1.5, 31.0) sm._update_streaming() targets = sm._compute_target_chunks() _check("Approaching lamppost at Z=31: chunk (0,0,0) is STILL in target set", targets.has(Vector3i(0, 0, 0))) # Clean up sm.queue_free() player.queue_free()