diff options
Diffstat (limited to 'world/chunk/ChunkLoader.gd')
-rw-r--r-- | world/chunk/ChunkLoader.gd | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/world/chunk/ChunkLoader.gd b/world/chunk/ChunkLoader.gd new file mode 100644 index 0000000..0ea422a --- /dev/null +++ b/world/chunk/ChunkLoader.gd @@ -0,0 +1,131 @@ +extends Node + +var world = null + +var Chunk = preload("res://world/chunk/Chunk.tscn") +var loaded_chunks = {} +var freed_chunks = {} +var chunk_thread = Thread.new() +var mtx = Mutex.new() +var sgnl = Semaphore.new() +var exit = false +var chunk_to_load = null +var chunk_to_len +var chunk_to_dummy + +func _ready(): + chunk_thread.start(self, "chunk_loader") + +func _exit_tree(): + mtx.lock() + exit = true + sgnl.post() + mtx.unlock() + chunk_thread.wait_to_finish() + +func v2_coords(coords:Vector3): + return Vector2(coords.x,coords.z) + +func chunk_coords(coords:Vector2): + return coords.snapped(Vector2(world.chunk_size,world.chunk_size)) + +func v3_coords(coords:Vector2): + return Vector3(coords.x,0.0,coords.y) + +func free_chunk(coords:Vector2): + var monument = ChunkGen.get_monument_at_chunk(coords) + if monument != null && monument.loaded_chunk != null && monument.loaded_chunk == coords: + return + if !loaded_chunks.has(coords): + return + freed_chunks[coords] = loaded_chunks[coords] + loaded_chunks.erase(coords) + +func clean_chunks(): + var cleaned = {} + for chunk in freed_chunks.keys(): + var c = freed_chunks[chunk].get_ref() + if c == null: + cleaned[chunk] = c + continue + c.queue_free() + for chunk in cleaned.keys(): + freed_chunks.erase(chunk) + +func chunk_update(): + var chunks = {} + var gen_center = -v2_coords(world.get_node("Chunks").transform.origin) + var gen_radius = world.lod_distance + var gen_radius_rounded = stepify(gen_radius, world.chunk_size) + for x in range(-gen_radius_rounded, gen_radius_rounded+world.chunk_size, world.chunk_size): + for y in range(-gen_radius_rounded, gen_radius_rounded+world.chunk_size, world.chunk_size): + var gen_coords = Vector2(x,y) + var coords_len = gen_coords.length() + if coords_len > gen_radius: + continue + var coords = chunk_coords(gen_coords + gen_center) + chunks[coords] = coords_len + var closest_unloaded_chunk = null + var closest_len = 0.0 + for chunk in chunks.keys(): + if !loaded_chunks.has(chunk): + var chunk_len = chunks[chunk] + if closest_unloaded_chunk == null || closest_len > chunk_len: + closest_unloaded_chunk = chunk + closest_len = chunk_len + if closest_unloaded_chunk != null: + var dummy = false + var monument = ChunkGen.get_monument_at_chunk(closest_unloaded_chunk) + if monument != null && monument.loaded_chunk != null: + dummy = true + mtx.lock() + if chunk_to_load == null: + chunk_to_load = closest_unloaded_chunk + chunk_to_len = closest_len + chunk_to_dummy = dummy + sgnl.post() + mtx.unlock() + for monument in ChunkGen.monuments: + if monument.loaded_chunk != null: + var loaded = false + for chunk in chunks.keys(): + if monument.chunks.has(chunk): + loaded = true + break + if !loaded: + monument.loaded_chunk = null + for chunk in loaded_chunks.keys(): + if !chunks.has(chunk): + free_chunk(chunk) + clean_chunks() + +func chunk_loader(): + while true: + sgnl.wait() + mtx.lock() + var x = exit + var coords = chunk_to_load + var lod = chunk_to_len + var dummy = chunk_to_dummy + mtx.unlock() + if x: + break + var chunk = Chunk.instance() + chunk.transform.origin = Vector3(coords.x,0.0,coords.y) + lod -= world.chunk_size + var tmp = world.get_node("Chunk") + chunk.lod = tmp.LOD.CLOSE if lod <= world.lod_close else tmp.LOD.MID if lod <= world.lod_mid else tmp.LOD.DISTANCE + ChunkGen.gen_chunk(chunk,dummy) + self.call_deferred("finish_chunk", chunk) + +func finish_chunk(chunk): + mtx.lock() + chunk_to_load = null + mtx.unlock() + world.get_node("Chunks").add_child(chunk) + var coords = v2_coords(chunk.transform.origin) + loaded_chunks[coords] = weakref(chunk) + var monument = ChunkGen.get_monument_at_chunk(coords) + if monument != null: + if monument.loaded_chunk == null: + monument.loaded_chunk = coords |