diff --git a/src/classes/basemodule.gd b/src/classes/basemodule.gd index 0117e8d..fa0cd5b 100644 --- a/src/classes/basemodule.gd +++ b/src/classes/basemodule.gd @@ -36,6 +36,9 @@ var initialized: bool = false ## CORE's replacement for [method Object._init] and [method Node._ready] ## It's [b]strongly[/b] recommended to initialize your module here. func _initialize() -> void: initialized = true +## Called when CORE is about to cleanup +## Use this function to free any children +func _cleanup() -> void: pass ## Called by [method Core.apply_configuration]. ## This should be used to update your module configuration. func _pull_config() -> void: pass diff --git a/src/core.gd b/src/core.gd index 0d70fda..100c926 100644 --- a/src/core.gd +++ b/src/core.gd @@ -31,6 +31,7 @@ const version_type: CoreTypes.VersionType = CoreTypes.VersionType.BETA const version_typerelease: int = 4 # Modules +const modules: Array[String] = [ "logger", "misc", "sms", "logui", "edl", "storage" ] ## Use this to access CORE's logging implementation. var logger: CoreBaseModule ## Use this to access various useful functions. @@ -72,58 +73,38 @@ func _ready() -> void: custom_modules_node.name = "Custom Modules" add_child(custom_modules_node) +# Cleanup +# Particularily useful during testing to cleanup stuff, or if you want to do some stupid stuff with CORE during runtime +func cleanup() -> void: + logger.infof("Core", "Cleaning up") + config.queue_free() + var modules_reverse: Array[String] = modules.duplicate() + modules_reverse.reverse() + for module in modules_reverse: + await get(module)._cleanup() + get(module).queue_free() + for module in custom_modules_node.get_children(): unregister_custom_module(module.name) + remove_child(custom_modules_node) + custom_modules_node.queue_free() + queue_free() + # Initialize modules ## Initializes all modules during the first initialization phase.[br] ## [br] ## [b]NEVER call this yourself! You will break everything and risk a crash![/b] func initialize_modules() -> void: - # Create Nodes - logger = CoreBaseModule.new() - misc = CoreBaseModule.new() - sms = CoreBaseModule.new() - logui = CoreBaseModule.new() - edl = CoreBaseModule.new() - storage = CoreBaseModule.new() - # Set names - logger.name = "Logger" - misc.name = "Misc" - sms.name = "SceneManagementSystem" - logui.name = "LogUI" - edl.name = "EasyDownLoader" - storage.name = "Storage" - # Set scripts - logger.set_script(ResourceLoader.load(basepath + "src/logger.gd")) - misc.set_script(ResourceLoader.load(basepath + "src/misc.gd")) - sms.set_script(ResourceLoader.load(basepath + "src/sms.gd")) - logui.set_script(ResourceLoader.load(basepath + "src/logui.gd")) - edl.set_script(ResourceLoader.load(basepath + "src/edl.gd")) - storage.set_script(ResourceLoader.load(basepath + "src/storage.gd")) - # Set reference to self - logger.core = self - misc.core = self - sms.core = self - logui.core = self - edl.core = self - storage.core = self - # Call _initialize() (workaround as modules cannot access "core" during _init()) - logger._initialize() - misc._initialize() - sms._initialize() - logui._initialize() - edl._initialize() - storage._initialize() + for module in modules: + set(module, CoreBaseModule.new()) + get(module).name = module + get(module).set_script(load(basepath + "src/" + module + ".gd")) + get(module).core = self + get(module)._initialize() # Inject modules into the SceneTree ## Injects CORE's builtin modules into the SceneTree.[br] ## [br] ## [b]NEVER call this yourself! You will break everything and risk a crash![/b] -func inject_modules() -> void: - add_child(logger) - add_child(misc) - add_child(sms) - add_child(logui) - add_child(edl) - add_child(storage) +func inject_modules() -> void: for module in modules: add_child(get(module)) # Wait for all modules to be fully initialized ## Wait for all builtin modules to be fully initialized.[br] @@ -140,12 +121,7 @@ func complete_init(no_success: bool = false) -> void: modsinit_custom = [] # Check builtin modules - if !logger.initialized: modsinit_builtin.append("logger") - if !misc.initialized: modsinit_builtin.append("misc") - if !sms.initialized: modsinit_builtin.append("sms") - if !logui.initialized: modsinit_builtin.append("logui") - if !edl.initialized: modsinit_builtin.append("edl") - if !storage.initialized: modsinit_builtin.append("storage") + for module in modules: if !get(module).initialized: modsinit_builtin.append(module) # Check custom modules for module_name in custom_modules: @@ -154,10 +130,8 @@ func complete_init(no_success: bool = false) -> void: # Print and sleep if modsinit_builtin.size() != 0 or modsinit_custom.size() != 0: print("Waiting for modules to finish initialization:") - if modsinit_builtin.size() != 0: - print(" Builtin: " + str(modsinit_builtin)) - if modsinit_custom.size() != 0: - print(" Custom: " + str(modsinit_custom)) + if modsinit_builtin.size() != 0: print(" Builtin: " + str(modsinit_builtin)) + if modsinit_custom.size() != 0: print(" Custom: " + str(modsinit_custom)) await get_tree().create_timer(1).timeout # Initialization complete @@ -194,8 +168,11 @@ func unregister_custom_module(module_name: String) -> void: if !custom_modules.has(module_name): logger.errorf("Core", "Unregistering module failed: A custom module with the name \"" + module_name + "\" does not exist.") return - custom_modules_node.remove_child(get_custom_module(module_name)) + var module: Node = get_custom_module(module_name) + await module._cleanup() + custom_modules_node.remove_child(module) custom_modules.erase(module_name) + module.queue_free() # Returns a custom module ## Returns a loaded custom module for access. @@ -211,6 +188,7 @@ func get_custom_module(module_name: String) -> CoreBaseModule: func reload_configuration(new_config: CoreConfiguration = CoreConfiguration.new()) -> void: var initialized = config != null if initialized: logger.verbf("Core", "Reloading CORE's configuration") + if config != null: config.queue_free() config = new_config if is_devmode(): # Override configuration in development mode config.logger_level = CoreTypes.LoggerLevel.VERB @@ -229,10 +207,7 @@ func apply_configuration() -> void: if !config.custom_modules: logger.verbf("Core", "Removing all custom modules (custom modules support is disabled)") for module in custom_modules: unregister_custom_module(module) - logger._pull_config() - misc._pull_config() - sms._pull_config() - logui._pull_config() + for module in modules: get(module)._pull_config() if config.custom_modules: for module in custom_modules: logger.diagf("Core", "Updating configuration for custom module \"" + module.name + "\"") diff --git a/src/edl.gd b/src/edl.gd index 3f11cf5..9ad8cd7 100644 --- a/src/edl.gd +++ b/src/edl.gd @@ -24,6 +24,15 @@ var list_queue: Dictionary = {} var list_active: Dictionary = {} var list_complete: Dictionary = {} +func _cleanup() -> void: + clean_queue() + clean_completed() + for child in get_children(): + if child.is_class("HTTPRequest"): + child.cancel_request() + await get_tree().process_frame + remove_child(child) + func generate_id() -> int: var id = randi() if list_queue.has(id) or list_active.has(id): return generate_id() @@ -75,11 +84,13 @@ func start_download(id: int, parse_utf8: bool) -> void: download.name = "Request #" + str(id) download.accept_gzip = true download.use_threads = true - var lambda: Callable = func(result: int, http_code: int, headers: PackedStringArray, body: PackedByteArray) -> void: + var lambda: Callable = func(result: int, http_code: int, headers: PackedStringArray, body: PackedByteArray, httprequest: HTTPRequest) -> void: logger.verbf("Edl", "Request " + str(id) + " completed\nResult: " + str(result) + "\nHTTP response code: " + str(http_code) + "\nHeaders: " + str(headers.size()) + "\nBody size: " + str(body.size()) + " Bytes // " + str(core.misc.byte2mib(body.size(), true)) + " MiB") list_complete.merge({ id: { "result": result, "http_code": http_code, "headers": headers, "body": body, "body_utf8": body.get_string_from_utf8() if !parse_utf8 else "" } }) list_active.erase(id) - download.connect("request_completed", lambda) + remove_child(httprequest) + httprequest.queue_free() + download.connect("request_completed", lambda.bind(download)) add_child(download) download.request(list_active[id]["url"], list_active[id]["headers"], list_active[id]["method"], list_active[id]["body"]) diff --git a/src/logui.gd b/src/logui.gd index 685de40..d922ec3 100644 --- a/src/logui.gd +++ b/src/logui.gd @@ -30,8 +30,8 @@ var font_bold: Font func _initialize() -> void: # Load fonts into memory - font_normal = ResourceLoader.load(core.basepath + "dist/FiraCode/Regular.ttf") - font_bold = ResourceLoader.load(core.basepath + "dist/FiraCode/Bold.ttf") + font_normal = load(core.basepath + "dist/FiraCode/Regular.ttf") + font_bold = load(core.basepath + "dist/FiraCode/Bold.ttf") # Create LogUI background = ColorRect.new() background.name = "LOGUI" @@ -59,17 +59,12 @@ func _initialize() -> void: # Mark as initialized initialized = true -func _pull_config() -> void: - background.visible = !core.config.headless and core.config.logui_enabled - background.color = core.config.logui_background_color - logrtl.add_theme_font_size_override("normal_font_size", core.config.logui_font_size) - logrtl.add_theme_font_size_override("bold_font_size", core.config.logui_font_size) - func _ready() -> void: # Add to SceneTree core.sms.add_child(background) core.sms.move_child(background, 0) background.add_child(logrtl) + # Hide VScrollBar var vsbar: VScrollBar = logrtl.get_child(0, true) vsbar.set_deferred("size", Vector2i(1, 1)) @@ -79,9 +74,22 @@ func _ready() -> void: vsbar.add_theme_stylebox_override("grabber", StyleBoxEmpty.new()) vsbar.add_theme_stylebox_override("grabber_highlight", StyleBoxEmpty.new()) vsbar.add_theme_stylebox_override("grabber_pressed", StyleBoxEmpty.new()) + # Connect log_event logger.connect("log_event", func(allowed: bool, _level: CoreTypes.LoggerLevel, _origin: String, _message: String, format: String) -> void: if allowed: logrtl.text = logrtl.text + format + "\n") +func _cleanup() -> void: + background.remove_child(logrtl) + core.sms.remove_child(background) + logrtl.queue_free() + background.queue_free() + +func _pull_config() -> void: + background.visible = !core.config.headless and core.config.logui_enabled + background.color = core.config.logui_background_color + logrtl.add_theme_font_size_override("normal_font_size", core.config.logui_font_size) + logrtl.add_theme_font_size_override("bold_font_size", core.config.logui_font_size) + func _process(_delta: float) -> void: if !core.config.headless: var window_size: Vector2i = DisplayServer.window_get_size() diff --git a/src/misc.gd b/src/misc.gd index a7e9fbc..e46a054 100644 --- a/src/misc.gd +++ b/src/misc.gd @@ -25,6 +25,7 @@ func quit_safely(exitcode: int = 0) -> void: logger.infof("Misc", "Shutting down (code " + str(exitcode) + ")") logger.diagf("Misc", "Waiting for log messages to be flushed") await get_tree().create_timer(0.25).timeout + await core.cleanup() get_tree().quit(exitcode) @warning_ignore("integer_division") diff --git a/src/sms.gd b/src/sms.gd index 7e0222d..c53ae3e 100644 --- a/src/sms.gd +++ b/src/sms.gd @@ -21,6 +21,7 @@ extends CoreBaseModule # Objects +const scene_nodes: Array[String] = ["debug", "cutscene", "menu", "main", "background"] var scenes_debug: Node = Node.new() var scenes_cutscene: Node = Node.new() var scenes_menu: Node = Node.new() @@ -31,20 +32,18 @@ var scenes_background: Node = Node.new() var scenes: Dictionary = {} func _initialize() -> void: - scenes_debug.name = "DEBUG" - scenes_cutscene.name = "CUTSCENE" - scenes_menu.name = "MENU" - scenes_main.name = "MAIN" - scenes_background.name = "BACKGROUND" - add_child(scenes_background) - add_child(scenes_main) - add_child(scenes_menu) - add_child(scenes_cutscene) - add_child(scenes_debug) + for scene in scene_nodes: + get("scenes_" + scene).name = scene.to_upper() + add_child(get("scenes_" + scene)) # Mark as initialized initialized = true +func _cleanup() -> void: + for scene in scene_nodes: + remove_child(get("scenes_" + scene)) + get("scenes_" + scene).queue_free() + func _pull_config() -> void: if core.config.headless: # Remove all scenes diff --git a/tests/custom_module.gd b/tests/custom_module.gd index bbe5beb..dd77bb0 100644 --- a/tests/custom_module.gd +++ b/tests/custom_module.gd @@ -6,6 +6,9 @@ func _initialize() -> void: logger.info("tests/custom_module.gd", "Module has been initialized") suite.callback = "_initialize" +func _cleanup() -> void: + logger.info("tests/custom_module.gd", "Cleaning module") + func _pull_config() -> void: logger.info("tests/custom_module.gd", "The configuration has been updated") suite.callback = "_pull_config"