Start adding async loading

This commit is contained in:
Hamcha 2020-07-13 02:20:09 +02:00
parent 209bafa5f1
commit 1c328e3e2e
Signed by: hamcha
GPG key ID: 41467804B19A3315
5 changed files with 159 additions and 5 deletions

147
Classes/ResourceQueue.gd Normal file
View file

@ -0,0 +1,147 @@
class_name ResourceQueue
var thread
var mutex
var sem
var time_max = 100 # Milliseconds.
var queue = []
var pending = {}
func _lock(_caller):
mutex.lock()
func _unlock(_caller):
mutex.unlock()
func _post(_caller):
sem.post()
func _wait(_caller):
sem.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:
VisualServer.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:
thread_process()
func start():
mutex = Mutex.new()
sem = Semaphore.new()
thread = Thread.new()
thread.start(self, "thread_func", 0)

View file

@ -6,6 +6,9 @@ class_name GameMap
var ship_direction = 0 var ship_direction = 0
var ship_speed = 0 var ship_speed = 0
var current_ship_position = Vector2.ZERO
var current_ship_target = Vector2.ZERO
var current_ship_direction = 0 var current_ship_direction = 0
var current_ship_speed = 0 var current_ship_speed = 0

View file

@ -1,6 +1,6 @@
extends Control extends Control
export var scale = 2 setget set_scale export var scale = 4 setget set_scale
export var upThreshold = 1.0/Engine.iterations_per_second export var upThreshold = 1.0/Engine.iterations_per_second
export var downThreshold = 1.0/30.0 export var downThreshold = 1.0/30.0

View file

@ -6,8 +6,6 @@ enum Map { RUNTIME, ODYSSEY }
export(Map) var mapToLoad = Map.RUNTIME export(Map) var mapToLoad = Map.RUNTIME
const runtimeRes = preload("res://Scenes/Maps/runtime.tscn")
const odysseyRes = preload("res://Scenes/Maps/odyssey.tscn")
const playerRes = preload("res://Actors/Player/Player.tscn") const playerRes = preload("res://Actors/Player/Player.tscn")
var map = null var map = null
@ -16,9 +14,9 @@ var player = null
func _ready(): func _ready():
match mapToLoad: match mapToLoad:
Map.RUNTIME: Map.RUNTIME:
map = runtimeRes.instance() map = load("res://Scenes/Maps/runtime.tscn").instance()
Map.ODYSSEY: Map.ODYSSEY:
map = odysseyRes.instance() map = load("res://Scenes/Maps/odyssey.tscn").instance()
add_child(map) add_child(map)
player = playerRes.instance() player = playerRes.instance()
player.is_controlled = true player.is_controlled = true

View file

@ -94,6 +94,11 @@ _global_script_classes=[ {
"language": "GDScript", "language": "GDScript",
"path": "res://Actors/Systems/Electricity/ElectricProbe.gd" "path": "res://Actors/Systems/Electricity/ElectricProbe.gd"
}, { }, {
"base": "Reference",
"class": "ResourceQueue",
"language": "GDScript",
"path": "res://Classes/ResourceQueue.gd"
}, {
"base": "Node2D", "base": "Node2D",
"class": "SpawnpointPlayer", "class": "SpawnpointPlayer",
"language": "GDScript", "language": "GDScript",
@ -122,6 +127,7 @@ _global_script_class_icons={
"PowerManager": "", "PowerManager": "",
"PowerNetwork": "", "PowerNetwork": "",
"ProbeElectric": "", "ProbeElectric": "",
"ResourceQueue": "",
"SpawnpointPlayer": "", "SpawnpointPlayer": "",
"UICommand": "" "UICommand": ""
} }