moved chunkgen to 2nd thread, initial solution

This commit is contained in:
Antti Hakkarainen 2023-02-13 21:24:55 +02:00
parent 675b451723
commit ad598f980e
7 changed files with 134 additions and 70 deletions

View file

@ -10,9 +10,12 @@ extends Node2D
# which is extremely slow in godot 4.0, 4096x4096 takes minutes to fill with set_cell() commands
var chunks:Dictionary = {}
var unready_chunks:Dictionary = {}
var window_width = DisplayServer.window_get_size(0).x
var distance = abs((window_width/(Globals.CHUNK_SIZE.x*Globals.TILE_SIZE_X)) / 2 +1 )
var mutex:Mutex
var semaphore:Semaphore
var thread:Thread
var exit_thread = false
func _init() -> void:
@ -20,44 +23,73 @@ func _init() -> void:
func _process(_delta):
# if !Globals.worlgen_ready || Globals.chunk_queue.size() > 64:
# return
update_chunks()
clean_up_chunks()
reset_chunks()
reset_chunks()
#print(self.get_child_count())
func _ready():
#thread = Thread.new()
#print(distance)
pass
mutex = Mutex.new()
semaphore = Semaphore.new()
exit_thread = false
thread = Thread.new()
thread.start(start_chunkgen, Thread.PRIORITY_NORMAL)
func start_chunkgen():
while true:
semaphore.wait()
mutex.lock()
var should_exit = exit_thread # Protect with Mutex.
mutex.unlock()
if should_exit:
break
if Globals.chunk_queue.size() > 0:
mutex.lock()
var vars = Globals.chunk_queue.pop_front()
mutex.unlock()
load_chunk(vars[0].y, vars[0].x, vars[1])
# Thread must be disposed (or "joined"), for portability.
func _exit_tree():
# Set exit condition to true.
mutex.lock()
exit_thread = true # Protect with Mutex.
mutex.unlock()
# Unblock by posting.
semaphore.post()
# Wait until it exits.
thread.wait_to_finish()
func add_chunk(x:int, y:int) -> void:
var key = str(y) + "," + str(x)
if chunks.has(key):
return
load_chunk(x, y, key)
func clean_up_chunks():
for key in chunks:
var chunk = chunks[key]
if chunk.should_remove:
chunk.queue_free()
chunks.erase(key)
func clear_chunk(pos:Vector2i) -> void:
self.chunks[pos.y][pos.x].clear()
func correction_factor(distance) -> float:
func correction_factor(d) -> float:
if Globals.CAMERA_ZOOM_LEVEL < 0.6:
return distance * 2.0
return d * 2.0
elif Globals.CAMERA_ZOOM_LEVEL > 1.0:
return distance
return d
else:
return distance * ( 1 + 2 * (1-Globals.CAMERA_ZOOM_LEVEL) )
return d * ( 1 + 2 * (1-Globals.CAMERA_ZOOM_LEVEL) )
func get_chunk(x:int, y:int):
var key = str(y) + "," + str(x)
@ -65,22 +97,26 @@ func get_chunk(x:int, y:int):
return chunks.get(key)
return null
func load_chunk(x:int, y:int, key:String):
var chunk = Chunk.new(x,y)
self.add_child(chunk)
func load_chunk(y:int, x:int, key):
var chunk = Chunk.new(y, x, false)
call_deferred("add_child", chunk)
mutex.lock()
chunks[key] = chunk
Globals.chunks_loaded += 1
mutex.unlock()
func reset_chunks():
# avoid trying to edit already removed chunks
mutex.lock()
for key in chunks:
chunks[key].should_remove = true
mutex.unlock()
func update_chunks():
func update_chunks():
var p_x = int(Globals.CAMERA_POSITION.x- Globals.CHUNK_SIZE.x) / Globals.TILE_SIZE_X / Globals.CHUNK_SIZE.x
var p_y = int(Globals.CAMERA_POSITION.y- Globals.CHUNK_SIZE.y) / Globals.TILE_SIZE_Y / Globals.CHUNK_SIZE.y
@ -88,13 +124,23 @@ func update_chunks():
# based on current zoom level.
var zoom_corrected = correction_factor(distance)
# iterate through all the chunks. if a chunk is in camera range,
# and it exists, it should not be removed
# if chunk should be in range and it doesn't exist, it will be
# created by adding the coords to a work queue
for y in Globals.map_size/Globals.CHUNK_SIZE.y:
for x in Globals.map_size/Globals.CHUNK_SIZE.x:
if (abs(x - p_x) <= zoom_corrected && abs(y - p_y) <= zoom_corrected):
add_chunk(x, y)
var chunk = get_chunk(x,y)
if chunk != null:
chunk.should_remove = false
if (abs(x - p_x) <= zoom_corrected && abs(y - p_y) <= zoom_corrected):
var key = str(y) + "," + str(x)
if chunks.has(key):
var chunk = get_chunk(x,y)
if chunk != null:
chunk.should_remove = false
else:
mutex.lock()
Globals.chunk_queue.push_back([Vector2i(x, y), key])
mutex.unlock()
semaphore.post()