refactor(M03): extract terrain chunk queue planner
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
class_name TerrainChunkGeometryQueuePlanner
|
||||
extends RefCounted
|
||||
|
||||
## Pure desired-operation planner for terrain chunk geometry queues.
|
||||
|
||||
const GODOT_WORLD_POSITION_SCRIPT := preload(
|
||||
"res://src/domain/coordinates/godot_world_position.gd"
|
||||
)
|
||||
|
||||
|
||||
## Returns fresh nearest-first create and stable-order remove request arrays.
|
||||
## The caller retains queue storage, execution order and every render side effect.
|
||||
func plan(tile_states: Dictionary, focus_position: RefCounted) -> Dictionary:
|
||||
var chunk_create_requests: Array = []
|
||||
var chunk_remove_requests: Array = []
|
||||
if (
|
||||
focus_position == null
|
||||
or focus_position.get_script() != GODOT_WORLD_POSITION_SCRIPT
|
||||
):
|
||||
return _create_plan(chunk_create_requests, chunk_remove_requests)
|
||||
|
||||
var focus_x_units := float(focus_position.get("x_units"))
|
||||
var focus_z_units := float(focus_position.get("z_units"))
|
||||
for tile_key_variant in tile_states.keys():
|
||||
var tile_key := String(tile_key_variant)
|
||||
var tile_state: Dictionary = tile_states[tile_key_variant]
|
||||
var current_chunks: Dictionary = tile_state["chunks"]
|
||||
var desired_lods: Dictionary = tile_state["desired_lods"]
|
||||
var desired_tile_lod := int(tile_state.get("desired_tile_lod", -1))
|
||||
|
||||
if desired_tile_lod >= 0:
|
||||
for chunk_id in current_chunks.keys():
|
||||
chunk_remove_requests.append({"tile": tile_key, "chunk": chunk_id})
|
||||
continue
|
||||
|
||||
for chunk_id in current_chunks.keys():
|
||||
if not desired_lods.has(chunk_id):
|
||||
chunk_remove_requests.append({"tile": tile_key, "chunk": chunk_id})
|
||||
continue
|
||||
if int(current_chunks[chunk_id]["lod"]) != int(desired_lods[chunk_id]):
|
||||
chunk_create_requests.append(_create_chunk_request(
|
||||
tile_key,
|
||||
chunk_id,
|
||||
int(desired_lods[chunk_id]),
|
||||
_resolve_chunk_origin(tile_state, int(chunk_id)),
|
||||
focus_x_units,
|
||||
focus_z_units
|
||||
))
|
||||
|
||||
for chunk_id in desired_lods.keys():
|
||||
if current_chunks.has(chunk_id):
|
||||
continue
|
||||
chunk_create_requests.append(_create_chunk_request(
|
||||
tile_key,
|
||||
chunk_id,
|
||||
int(desired_lods[chunk_id]),
|
||||
_resolve_chunk_origin(tile_state, int(chunk_id)),
|
||||
focus_x_units,
|
||||
focus_z_units
|
||||
))
|
||||
|
||||
chunk_create_requests.sort_custom(func(
|
||||
left_request: Dictionary,
|
||||
right_request: Dictionary
|
||||
) -> bool:
|
||||
return float(left_request["dist_sq"]) < float(right_request["dist_sq"])
|
||||
)
|
||||
return _create_plan(chunk_create_requests, chunk_remove_requests)
|
||||
|
||||
|
||||
func _resolve_chunk_origin(tile_state: Dictionary, chunk_id: int) -> Vector3:
|
||||
var chunks: Array = tile_state["data"].get("chunks", [])
|
||||
if chunk_id >= 0 and chunk_id < chunks.size():
|
||||
var chunk: Dictionary = chunks[chunk_id]
|
||||
if not chunk.is_empty():
|
||||
return chunk.get("origin", Vector3.ZERO)
|
||||
return tile_state.get("origin", Vector3.ZERO)
|
||||
|
||||
|
||||
func _create_chunk_request(
|
||||
tile_key: String,
|
||||
chunk_id: Variant,
|
||||
desired_lod: int,
|
||||
chunk_origin: Vector3,
|
||||
focus_x_units: float,
|
||||
focus_z_units: float
|
||||
) -> Dictionary:
|
||||
var delta_x_units := chunk_origin.x - focus_x_units
|
||||
var delta_z_units := chunk_origin.z - focus_z_units
|
||||
return {
|
||||
"tile": tile_key,
|
||||
"chunk": chunk_id,
|
||||
"lod": desired_lod,
|
||||
"dist_sq": delta_x_units * delta_x_units + delta_z_units * delta_z_units,
|
||||
}
|
||||
|
||||
|
||||
func _create_plan(chunk_create_requests: Array, chunk_remove_requests: Array) -> Dictionary:
|
||||
return {
|
||||
"create_requests": chunk_create_requests,
|
||||
"remove_requests": chunk_remove_requests,
|
||||
}
|
||||
Reference in New Issue
Block a user