resource_queue.gd 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. var thread
  2. var mutex
  3. var sem
  4. var time_max = 100 # msec
  5. var queue = []
  6. var pending = {}
  7. func _lock(caller):
  8. mutex.lock()
  9. func _unlock(caller):
  10. mutex.unlock()
  11. func _post(caller):
  12. sem.post()
  13. func _wait(caller):
  14. sem.wait()
  15. func queue_resource(path, p_in_front = false):
  16. _lock("queue_resource")
  17. if path in pending:
  18. _unlock("queue_resource")
  19. return
  20. elif ResourceLoader.has(path):
  21. var res = ResourceLoader.load(path)
  22. pending[path] = res
  23. _unlock("queue_resource")
  24. return
  25. else:
  26. var res = ResourceLoader.load_interactive(path)
  27. res.set_meta("path", path)
  28. if p_in_front:
  29. queue.insert(0, res)
  30. else:
  31. queue.push_back(res)
  32. pending[path] = res
  33. _post("queue_resource")
  34. _unlock("queue_resource")
  35. return
  36. func cancel_resource(path):
  37. _lock("cancel_resource")
  38. if path in pending:
  39. if pending[path] extends ResourceInteractiveLoader:
  40. queue.erase(pending[path])
  41. pending.erase(path)
  42. _unlock("cancel_resource")
  43. func get_progress(path):
  44. _lock("get_progress")
  45. var ret = -1
  46. if path in pending:
  47. if pending[path] extends ResourceInteractiveLoader:
  48. ret = float(pending[path].get_stage()) / float(pending[path].get_stage_count())
  49. else:
  50. ret = 1.0
  51. _unlock("get_progress")
  52. return ret
  53. func is_ready(path):
  54. var ret
  55. _lock("is_ready")
  56. if path in pending:
  57. ret = !(pending[path] extends ResourceInteractiveLoader)
  58. else:
  59. ret = false
  60. _unlock("is_ready")
  61. return ret
  62. func _wait_for_resource(res, path):
  63. _unlock("wait_for_resource")
  64. while true:
  65. VS.flush()
  66. OS.delay_usec(16000) # wait 1 frame
  67. _lock("wait_for_resource")
  68. if queue.size() == 0 || queue[0] != res:
  69. return pending[path]
  70. _unlock("wait_for_resource")
  71. func get_resource(path):
  72. _lock("get_resource")
  73. if path in pending:
  74. if pending[path] extends ResourceInteractiveLoader:
  75. var res = pending[path]
  76. if res != queue[0]:
  77. var pos = queue.find(res)
  78. queue.remove(pos)
  79. queue.insert(0, res)
  80. res = _wait_for_resource(res, path)
  81. pending.erase(path)
  82. _unlock("return")
  83. return res
  84. else:
  85. var res = pending[path]
  86. pending.erase(path)
  87. _unlock("return")
  88. return res
  89. else:
  90. _unlock("return")
  91. return ResourceLoader.load(path)
  92. func thread_process():
  93. _wait("thread_process")
  94. _lock("process")
  95. while queue.size() > 0:
  96. var res = queue[0]
  97. _unlock("process_poll")
  98. var ret = res.poll()
  99. _lock("process_check_queue")
  100. if ret == ERR_FILE_EOF || ret != OK:
  101. var path = res.get_meta("path")
  102. if path in pending: # else it was already retrieved
  103. pending[res.get_meta("path")] = res.get_resource()
  104. queue.erase(res) # something might have been put at the front of the queue while we polled, so use erase instead of remove
  105. _unlock("process")
  106. func thread_func(u):
  107. while true:
  108. thread_process()
  109. func start():
  110. mutex = Mutex.new()
  111. sem = Semaphore.new()
  112. thread = Thread.new()
  113. thread.start(self, "thread_func", 0)