Skip to content

Instantly share code, notes, and snippets.

@derkork
Created April 22, 2021 09:45
Show Gist options
  • Save derkork/9a6933d5f534d4d663e8c8b382f09024 to your computer and use it in GitHub Desktop.
Save derkork/9a6933d5f534d4d663e8c8b382f09024 to your computer and use it in GitHub Desktop.
Godot Resource Queue with Signals
class_name ResourceQueue
extends Node
signal loaded(path,resource)
signal progress(path, current, total)
var _thread:Thread
var _mutex:Mutex
var _sem:Semaphore
var _queue = []
var _pending = {}
func _init():
_mutex = Mutex.new()
_sem = Semaphore.new()
_thread = Thread.new()
_thread.start(self, "_thread_func", 0)
func queue_resource(path:String, p_in_front := false):
_lock("queue_resource")
if path in _pending:
_unlock("queue_resource")
return
elif ResourceLoader.has_cached(path):
var res = ResourceLoader.load(path)
call_deferred("emit_loaded", path, res)
_unlock("queue_resource")
return
else:
var res = ResourceLoader.load_interactive(path)
res.set_meta("path", path)
if p_in_front:
_queue.insert(0, res)
else:
_queue.push_back(res)
_pending[path] = res
_post("queue_resource")
_unlock("queue_resource")
return
func cancel_resource(path):
_lock("cancel_resource")
if path in _pending:
_queue.erase(_pending[path])
_pending.erase(path)
_unlock("cancel_resource")
func _emit_loaded(path:String, resource):
emit_signal("loaded", path, resource)
func _emit_progress(path:String, current:int, total:int) -> void:
emit_signal("progress", path, current, total)
func _lock(_caller):
_mutex.lock()
func _unlock(_caller):
_mutex.unlock()
func _post(_caller):
_sem.post()
func _wait(_caller):
_sem.wait()
func _thread_process():
_wait("thread_process")
_lock("process")
while _queue.size() > 0:
var loader = _queue[0]
var path = loader.get_meta("path")
_unlock("process_poll")
var ret = loader.poll()
call_deferred("_emit_progress", path, loader.get_stage(), loader.get_stage_count())
_lock("process_check_queue")
if ret == ERR_FILE_EOF || ret != OK:
_pending.erase(path)
call_deferred("_emit_loaded", path, loader.get_resource())
# Something might have been put at the front of the queue while
# we polled, so use erase instead of remove.
_queue.erase(loader)
_unlock("process")
func _thread_func(_u):
while true:
_thread_process()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment