123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- extends Node
- var thread
- var mutex
- var semaphore
- var exit_thread = false
- var time_max = 100 # Milliseconds.
- var queue = []
- var pending = {}
- func _lock(_caller):
- mutex.lock()
- func _unlock(_caller):
- mutex.unlock()
- func _post(_caller):
- semaphore.post()
- func _wait(_caller):
- semaphore.wait()
- func queue_resource(path, 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)
- pending[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:
- if pending[path] is ResourceInteractiveLoader:
- queue.erase(pending[path])
- pending.erase(path)
- _unlock("cancel_resource")
- func get_progress(path):
- _lock("get_progress")
- var ret = -1
- if path in pending:
- if pending[path] is ResourceInteractiveLoader:
- ret = float(pending[path].get_stage()) / float(pending[path].get_stage_count())
- else:
- ret = 1.0
- _unlock("get_progress")
- return ret
- func is_ready(path):
- var ret
- _lock("is_ready")
- if path in pending:
- ret = !(pending[path] is ResourceInteractiveLoader)
- else:
- ret = false
- _unlock("is_ready")
- return ret
- func _wait_for_resource(res, path):
- _unlock("wait_for_resource")
- while true:
- RenderingServer.force_sync()
- OS.delay_usec(16000) # Wait approximately 1 frame.
- _lock("wait_for_resource")
- if queue.size() == 0 || queue[0] != res:
- return pending[path]
- _unlock("wait_for_resource")
- func get_resource(path):
- _lock("get_resource")
- if path in pending:
- if pending[path] is ResourceInteractiveLoader:
- var res = pending[path]
- if res != queue[0]:
- var pos = queue.find(res)
- queue.remove(pos)
- queue.insert(0, res)
- res = _wait_for_resource(res, path)
- pending.erase(path)
- _unlock("return")
- return res
- else:
- var res = pending[path]
- pending.erase(path)
- _unlock("return")
- return res
- else:
- _unlock("return")
- return ResourceLoader.load(path)
- func thread_process():
- _wait("thread_process")
- _lock("process")
- while queue.size() > 0:
- var res = queue[0]
- _unlock("process_poll")
- var ret = res.poll()
- _lock("process_check_queue")
- if ret == ERR_FILE_EOF || ret != OK:
- var path = res.get_meta("path")
- if path in pending: # Else, it was already retrieved.
- pending[res.get_meta("path")] = res.get_resource()
- # Something might have been put at the front of the queue while
- # we polled, so use erase instead of remove.
- queue.erase(res)
- _unlock("process")
- func thread_func(_u):
- while true:
- mutex.lock()
- var should_exit = exit_thread # Protect with Mutex.
- mutex.unlock()
- if should_exit:
- break
- thread_process()
- func start():
- mutex = Mutex.new()
- semaphore = Semaphore.new()
- thread = Thread.new()
- thread.start(self, "thread_func", 0)
- # Triggered by calling "get_tree().quit()".
- func _exit_tree():
- mutex.lock()
- exit_thread = true # Protect with Mutex.
- mutex.unlock()
- # Unblock by posting.
- semaphore.post()
- # Wait until it exits.
- thread.wait_to_finish()
|