class_name Game extends Node ## Wrapper for the game application @export var start_scene: String = "res://src/ui/menus/title_screen/title_screen.tscn" var _loading_resources := {} @onready var viewport: GameViewportContainer = %ViewportContainer @onready var sfx: GameSFX = %SFX @onready var content: Node = %Content @onready var loader_transition: AnimationPlayer = %LoaderTransition @onready var loading_screen: Control = %LoadingScreen static var group := "GameGroup" # hey i'm group ## Typesafe accessor for GameSettings singleton static var settings: GameSettingsType: get: return GameSettings class Promise: var _callbacks: Array[Callable] = [] var _end_callbacks: Array[Callable] = [] func then(fn: Callable) -> Promise: _callbacks.push_back(fn) return self func finally(fn: Callable) -> Promise: _end_callbacks.push_back(fn) return self func resolve(res: Variant) -> void: for fn: Callable in _callbacks + _end_callbacks: fn.call(res) class ScenePromise: extends Promise func resolve(res: Variant) -> void: @warning_ignore("unsafe_cast") var instance: Node = (res as PackedScene).instantiate() super.resolve(instance) func _initial_load() -> void: queue_scene(start_scene) func _ready() -> void: call_deferred("_initial_load") ## Unload the running scene & queue up a new scene to be loaded in the background. ## ## The loading screen will be shown until the scene is loaded. func queue_scene(path: String) -> Promise: return queue_load(path, ScenePromise.new(), "PackedScene").finally(_finish_scene_load) ## Queue a resource to be loaded in the background. ## ## Returns a `Promise` which can be used to attach callbacks ## which will be called with the resource after it is loaded. func queue_load(path: String, promise: Promise = null, type_hint: String = "") -> Promise: if not promise: promise = Promise.new() _loading_resources[path] = promise ResourceLoader.load_threaded_request(path, type_hint) return promise func _unload_content() -> void: for child: Node in content.get_children(): child.queue_free() func _finish_scene_load(instance: Node) -> void: content.add_child(instance) instance.reparent(content) func _process(_delta: float) -> void: if _loading_resources and not loading_screen.visible: loader_transition.play("fade_in") if loader_transition.is_playing(): return for key: String in _loading_resources.keys(): match ResourceLoader.load_threaded_get_status(key): ResourceLoader.THREAD_LOAD_LOADED: @warning_ignore("unsafe_cast") (_loading_resources[key] as Promise).resolve(ResourceLoader.load_threaded_get(key)) _loading_resources.erase(key) ResourceLoader.THREAD_LOAD_FAILED: assert(false, "Failed loading resource: " + key) ResourceLoader.THREAD_LOAD_INVALID_RESOURCE: assert(false, "Can't load invalid resource: " + key) _: # Continue loading pass if not _loading_resources and loading_screen.visible: loader_transition.play("fade_out")