class_name World extends Node3D @onready var noise := FastNoiseLite.new() var chunks_to_generate: Array[Vector3i] = [] var chunks_to_update: Array[Vector3i] = [] var active_generate_task_id: int = -1 var active_update_task_id: int = -1 var player_last_chunk := Vector3i.ZERO var chunk_generation_radius := Vector3i(2, 2, 2) @onready var chunks_container := $Chunks func _ready() -> void: Global.player = $Player noise.seed = randi() var world_size := Vector3i(2, 1, 2) for column in range(world_size.y, 0, -1): for row in range(- world_size.x * 0.5, world_size.x * 0.5): for depth in range(- world_size.z * 0.5, world_size.z * 0.5): chunks_to_generate.append(Vector3i(row, column, depth)) # TODO: 2*1*2 worldgen on main thread # TODO: show loading anim. how? # TODO: worldgen not on main thread. # TODO: get number of chunks to be gen # TODO: ++number and show progress % func _process(_delta: float) -> void: if chunks_to_generate.size() > 0: if active_generate_task_id == -1: active_generate_task_id = WorkerThreadPool.add_task(generate_chunk_task.bind(0)) else: if WorkerThreadPool.is_task_completed(active_generate_task_id): WorkerThreadPool.wait_for_task_completion(active_generate_task_id) chunks_to_generate.remove_at(0) active_generate_task_id = -1 if chunks_to_update.size() > 0: if active_update_task_id == -1: active_update_task_id = WorkerThreadPool.add_group_task(update_chunk_task, chunks_to_update.size()) else: if WorkerThreadPool.is_group_task_completed(active_update_task_id): WorkerThreadPool.wait_for_group_task_completion(active_update_task_id) chunks_to_update.remove_at(0) active_update_task_id = -1 func _physics_process(_delta: float) -> void: if player_last_chunk != Global.player.current_chunk_position: player_last_chunk = Global.player.current_chunk_position var chunks_in_radius := [] for x in range(- chunk_generation_radius.x * 0.5, chunk_generation_radius.x * 0.5 + 1): for y in range(- chunk_generation_radius.y * 0.5, chunk_generation_radius.y * 0.5 + 1): for z in range(- chunk_generation_radius.z * 0.5, chunk_generation_radius.z * 0.5 + 1): var chunk_to_check := Global.player.current_chunk_position + Vector3i(x, y, z) chunks_in_radius.append(chunk_to_check) # generate new or re-generate existing nodes for p in chunks_in_radius: if not Chunk.chunk_exists(p): chunks_to_generate.append(p) elif not chunks_container.has_node("Chunk_%s_%s_%s" % [p.x, p.y, p.z]): chunks_to_generate.append(p) # remove surplus nodes for node: Chunk in chunks_container.get_children(): if not chunks_in_radius.has(node.grid_position): chunks_container.remove_child(node) func generate_chunk_task(index: int) -> void: update_chunk(chunks_to_generate[index]) func update_chunk_task(index: int) -> void: update_chunk(chunks_to_update[index]) func update_chunk(chunk_position: Vector3i) -> void: if Chunk.chunk_exists(chunk_position): var chunk: Chunk = Global.chunks[chunk_position] chunk.generate_mesh() chunk.update_mesh.call_deferred() (func(): if not chunks_container.has_node("Chunk_%s_%s_%s" % [chunk_position.x, chunk_position.y, chunk_position.z]): chunk.add_to(chunks_container) ).call_deferred() else: var chunk := create_chunk(chunk_position) chunk.generate_block_data(chunk_position.x, chunk_position.y, chunk_position.z) chunk.generate_mesh() chunk.add_to.call_deferred(chunks_container) func create_chunk(chunk_position: Vector3i) -> Chunk: var chunk: Chunk = preload("res://chunk.tscn").instantiate() chunk.noise = noise Global.chunks[chunk_position] = chunk return chunk func add_block(target_position: Vector3, normal: Vector3, block_type: Block.Type = Block.Type.AIR): var chunk_idx := Chunk.global_to_chunk(target_position + normal, Vector3.ZERO) var chunk: Chunk if Chunk.chunk_exists(chunk_idx): chunk = Global.chunks[chunk_idx] else: chunk = create_chunk(Vector3(chunk_idx.x, chunk_idx.y, chunk_idx.z)) chunk.generate_block_data(chunk_idx.x, chunk_idx.y, chunk_idx.z, true) chunk.add_to.call_deferred(self) var block_chunk_idx := Chunk.global_to_chunk_block(target_position + normal, normal) chunk.add_block(block_chunk_idx, block_type) chunks_to_update.append(chunk.grid_position) func remove_block(target_position: Vector3, normal: Vector3): var chunk_idx := Chunk.global_to_chunk(target_position, normal) if Chunk.chunk_exists(chunk_idx): var chunk: Chunk = Global.chunks[chunk_idx] var block_chunk_idx := Chunk.global_to_chunk_block(target_position, normal) chunk.remove_block(block_chunk_idx) chunks_to_update.append(chunk.grid_position) chunks_to_update.append_array(chunk.get_bordering_chunks(block_chunk_idx).filter(func(item): return Chunk.chunk_exists(item) ))