From 99efd65300a074fab1d722819ee566e2225767bd Mon Sep 17 00:00:00 2001 From: JeremyStarTM Date: Wed, 17 Apr 2024 16:37:18 +0200 Subject: [PATCH] Update to f5e50b1f6b3d5e9f5d4c74fd32ac536e46143804 --- src/classes/config.gd | 20 +++++++ src/core.gd | 98 +++++++++++++++++++++++++--------- src/erm.gd | 14 ++--- src/logger.gd | 18 ++++--- src/misc.gd | 121 ++++++++++++++++++++++++++++++++++++++++++ src/sms.gd | 112 ++++++++++++++++++-------------------- src/storage.gd | 8 ++- 7 files changed, 283 insertions(+), 108 deletions(-) diff --git a/src/classes/config.gd b/src/classes/config.gd index 1edfe7f..ea358bb 100644 --- a/src/classes/config.gd +++ b/src/classes/config.gd @@ -45,6 +45,18 @@ class_name CoreConfiguration @export var logui_background_color: Color ## What font size the graphical log should have. @export var logui_font_size: int + +@export_category("Miscellaneous") +## Shows or hides the type when calling [code]stringify_variables[/code]. +@export var misc_stringify_show_type: bool +## Determines how [code]stringify_variables[/code] should display [class Color] variables.[br] +## Will display colors from [code]0[/code] to [code]255[/code] if [code]true[/code] or from [code]-1.0[/code] to [code]1.0[/code] if [code]false[/code]. +@export var misc_stringify_color_range8: bool +## Determines if [class Array]s should be processed by [code]stringify_variables[/code]. +@export var misc_stringify_array: bool +## Determines if [class Dictionary]s should be processed by [code]stringify_variables[/code]. +@export var misc_stringify_dictionary: bool + @export_category("Easy Request Maker") ## Determines how unsecure requests should be handled. @export var erm_unsecure_requests: CoreTypes.BlockadeLevel @@ -63,9 +75,17 @@ func _init() -> void: logger_format = "%color%[%time%] [%level% %origin%] %message%" logger_newlines_override = true logger_newlines_sizelimit = 40 + # Log UI logui_enabled = true logui_background_color = Color.BLACK # To disable the background, use Color.TRANSPARENT logui_font_size = 14 + + # Misc + misc_stringify_show_type = true + misc_stringify_color_range8 = true + misc_stringify_array = true + misc_stringify_dictionary = true + # Easy Request Maker erm_unsecure_requests = CoreTypes.BlockadeLevel.BLOCK diff --git a/src/core.gd b/src/core.gd index 4b8e3fc..37c6a6c 100644 --- a/src/core.gd +++ b/src/core.gd @@ -57,18 +57,16 @@ var storage: CoreBaseModule ## Stores the path to CORE's installation directory.[br] ## [b]Danger: [i]Don't modify this.[/i][/b] var basepath: String -## Contains a list of all loaded custom modules.[br] -## [b]Danger: [i]Don't modify this.[/i][/b] +# Contains a list of all registered cleanup hooks. +var cleanup_hooks: Dictionary = {} +# Contains a list of all loaded custom modules. var custom_modules: Dictionary = {} -## Contains the node holding all custom modules as children.[br] -## [b]Danger: [i]Don't modify this.[/i][/b] +# Contains the node holding all custom modules as children. var custom_modules_node: Node -## The CORE Object's logger instance. -## [b]Danger: [i]Don't modify this.[/i][/b] +# The CORE Object's logger instance. var loggeri: CoreLoggerInstance # +++ initialization +++ -## Handles the preinitialization part. Does stuff like checking the engine version, loading the config and loading all modules into memory. func _init(new_config: CoreConfiguration = CoreConfiguration.new()) -> void: name = "CORE" if !check_godot_version(): return @@ -79,8 +77,6 @@ func _init(new_config: CoreConfiguration = CoreConfiguration.new()) -> void: apply_configuration() initialize_scheduler() -## Handles the initialization part. Injects the builtin modules into the SceneTree and makes sure custom modules can be loaded properly.[br] -## [b]Danger: [i]Don't call this.[/i][/b] func _ready() -> void: inject_modules() custom_modules_node.name = "Custom Modules" @@ -89,8 +85,7 @@ func _ready() -> void: add_child(scheduler) get_tree().auto_accept_quit = false -## Initializes all built-in modules during the preinitialization phase.[br] -## [b]Danger: [i]Don't call this.[/i][/b] +# Initializes all built-in modules during the preinitialization phase. func initialize_modules() -> void: for module in modules: set(module, CoreBaseModule.new()) @@ -100,12 +95,10 @@ func initialize_modules() -> void: get(module).loggeri = logger.get_instance(basepath.replace("res://", "") + "src/" + module + ".gd", get(module)) get(module)._initialize() -## Injects CORE's builtin modules into the SceneTree.[br] -## [b]Danger: [i]Don't call this.[/i][/b] +# Injects CORE's builtin modules into the SceneTree. func inject_modules() -> void: for module in modules: add_child(get(module)) -## Initializes the framework scheduler. -## [b]Danger: [i]Don't call this.[/i][/b] +# Initializes the framework scheduler. func initialize_scheduler() -> void: scheduler = Timer.new() scheduler.name = "Scheduler" @@ -163,8 +156,7 @@ func reload_configuration(new_config: CoreConfiguration = CoreConfiguration.new( if initialized: loggeri.verb("Overrode configuration (development mode)") if initialized: apply_configuration() -## Applies the a configuration.[br] -## [b]Danger: [i]Don't call this.[/i][/b] +# Applies a new configuration. func apply_configuration() -> void: if loggeri != null: loggeri.verb("Applying configuration") if is_devmode() and loggeri != null: loggeri.warn("The CORE Framework is in development mode. Here be dragons!") @@ -210,7 +202,7 @@ func unregister_custom_module(module_name: String) -> void: if !custom_modules.has(module_name): loggeri.error("Unregistering module failed: A custom module with the name \"" + module_name + "\" does not exist.") return - var module: Node = get_custom_module(module_name) + var module: Node = custom_modules[module_name] await module._cleanup() module.loggeri.queue_free() custom_modules_node.remove_child(module) @@ -226,23 +218,80 @@ func get_custom_module(module_name: String) -> CoreBaseModule: return null return custom_modules[module_name] -# +++ etc ++ +# +++ cleanup ++ ## Makes sure that CORE does not leak memory on shutdown/unload.[br] -## Unloads all custom modules, built-in modules, frees any of CORE's classes and lastly itself. +## Unloads all custom modules, built-in modules, frees any of CORE's classes and lastly itself.[br] +## Only call this function if you're sure that your application or game no longer uses the CORE Framework. func cleanup() -> void: loggeri.info("Cleaning up") - for module in custom_modules_node.get_children(): unregister_custom_module(module.name) + loggeri.verb("Calling cleanup hooks") + for hook in cleanup_hooks: + if !cleanup_hooks[hook].is_valid(): + loggeri.error("Cleanup hook #" + str(hook) + " is invalid") + else: + loggeri.diag("Calling cleanup hook #" + str(hook)) + await cleanup_hooks[hook].call() + loggeri.verb("Unregistering custom modules") + for module in custom_modules_node.get_children(): await unregister_custom_module(module.name) + loggeri.verb("Removing custom module support") remove_child(custom_modules_node) custom_modules_node.queue_free() + loggeri.verb("Unloading built-in modules") var modules_reverse: Array[String] = modules.duplicate() modules_reverse.reverse() for module in modules_reverse: await get(module)._cleanup() - get(module).loggeri.queue_free() get(module).queue_free() + print("Freeing configuration") config.queue_free() + await get_tree().process_frame + print("Freeing") queue_free() +# Generates a new cleanup hook id +func _generate_hook_id() -> int: + var id = randi() + if cleanup_hooks.has(id): + loggeri.warn("New cleanup hook id #" + str(id) + " is already taken") + return _generate_hook_id() + elif id == -1: + loggeri.warn("Invalid cleanup hook id '-1'") + return _generate_hook_id() + return id + +## Registers a new cleanup hook.[br] +## Returns the hook id. +func register_cleanup_hook(callable: Callable) -> int: + if !callable.is_valid(): + loggeri.error("Could not add cleanup hook: Callable is not valid") + return -1 + + var id: int = _generate_hook_id() + loggeri.verb("Adding new cleanup hook #" + str(id)) + cleanup_hooks.merge({ id: callable }) + return id + +## Unregisters a cleanup hook by it's id. +func unregister_cleanup_hook_by_id(id: int) -> bool: + if !cleanup_hooks.has(id): + loggeri.error("Could not remove cleanup hook (id): Hook #" + str(id) + " does not exist") + return false + loggeri.verb("Removed cleanup hook #" + str(id) + " (id)") + cleanup_hooks.erase(id) + return true + +## Unregisters a cleanup hook by it's reference. +func unregister_cleanup_hook_by_ref(callable: Callable) -> bool: + var id: Variant = cleanup_hooks.find_key(callable) + if id == null: + loggeri.error("Could not remove cleanup hook (ref): Could not find a matching hook") + return false + if typeof(id) != TYPE_INT: await loggeri.crash("Could not remove cleanup hook (ref): find_key did not return an integer (returned '" + str(id) + "')") + loggeri.verb("Removed cleanup hook #" + str(id) + " (ref)") + cleanup_hooks.erase(id) + return true + +# +++ etc +++ ## Returns if the framework is in development mode. func is_devmode() -> bool: return config.development @@ -299,8 +348,7 @@ func get_version_semantic() -> Array[int]: CoreTypes.VersionType.ALPHA: version_type_int = 0 return [version_version, version_type_int, version_typerelease] -## Determines CORE's installation/base path.[br] -## [b]Danger: [i]Don't call this.[/i][/b] +# Determines CORE's installation/base path. func determine_basepath() -> bool: if FileAccess.file_exists("res://.corebasepath"): basepath = "res://" @@ -313,7 +361,6 @@ func determine_basepath() -> bool: return false return true -# Checks Godot's version ## Checks compatibility with the running version. func check_godot_version() -> bool: var version: Dictionary = Engine.get_version_info() @@ -343,6 +390,7 @@ func quit_safely(exitcode: int = 0) -> void: await cleanup() get_tree().quit(exitcode) +# Just ignore this. func _notification(what) -> void: match(what): NOTIFICATION_WM_CLOSE_REQUEST: diff --git a/src/erm.gd b/src/erm.gd index a242139..db0dcfd 100644 --- a/src/erm.gd +++ b/src/erm.gd @@ -18,14 +18,11 @@ ## Allows for awaited, batched and oneline requests. extends CoreBaseModule -## Contains a list of all queued downloads.[br] -## [b]Danger: [i]Don't modify this[/i][/b]. +# Contains a list of all queued downloads. var list_queue: Dictionary = {} -## Contains a list of all active downloads.[br] -## [b]Danger: [i]Don't modify this[/i][/b]. +# Contains a list of all active downloads. var list_active: Dictionary = {} -## Contains a liust of all completed downloads.[br] -## [b]Danger: [i]Don't modify this[/i][/b]. +# Contains a liust of all completed downloads. var list_complete: Dictionary = {} ## Determines how unsecure requests should be handled. @@ -107,7 +104,7 @@ func batch_awaited_request(urls: PackedStringArray, parse_utf8: bool, method: HT list_complete.erase(id) return dldata -## Internal function, do not call +# Does the work, but in a thread. func _batch_awaited_request(url: String, parse_utf8: bool, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), data: String = "") -> int: var id: int = create_request(url, method, headers, data) start_request(id, parse_utf8) @@ -116,8 +113,7 @@ func _batch_awaited_request(url: String, parse_utf8: bool, method: HTTPClient.Me return id # +++ internal +++ -## Returns a new download id.[br] -## [b]Danger: [i]Don't call this.[/i][/b] +# Returns a new download id. func generate_id() -> int: var id = randi() if list_queue.has(id) or list_active.has(id): diff --git a/src/logger.gd b/src/logger.gd index e0ad18e..5631d13 100644 --- a/src/logger.gd +++ b/src/logger.gd @@ -23,9 +23,7 @@ extends CoreBaseModule signal log_event -## Keeps track of all logger instances. -## Unused instances will be cleaned periodically. -## [b]Danger: [i]Don't modify this.[/i][/b] +# Keeps track of all logger instances. Unused instances will be cleaned periodically by CORE's scheduler. var instances: Array[CoreLoggerInstance] = [] ## Used to determine if running in verbose/command line mode.[br] @@ -46,16 +44,21 @@ var config_newlines_sizelimit: int # +++ module +++ func _cleanup() -> void: - _schedule() - await get_tree().process_frame + for instance in instances: + if is_instance_valid(instance): + loggeri.diag("Removing instance '" + instance.name + "'") + instance.queue_free() func _schedule() -> void: + var instances_remove_enty: Array[CoreLoggerInstance] = [] for instance in instances: if !is_instance_valid(instance): continue if !is_instance_valid(instance.parent): loggeri.diag("Removing instance '" + instance.name + "'") instance.queue_free() - instances.remove_at(instances.find(instance)) + instances_remove_enty.append(instance) + for instance in instances_remove_enty: + instances.remove_at(instances.find(instance)) func _pull_config() -> void: config_level = core.config.logger_level @@ -65,8 +68,7 @@ func _pull_config() -> void: config_newlines_sizelimit = core.config.logger_newlines_sizelimit # +++ logging +++ -## The main logging function that does the heavy lifting.[br] -## [b]Danger: [i]Don't call this.[/i][/b] +# The main logging function that does the heavy lifting. func _log(level: CoreTypes.LoggerLevel, origin: String, message: String) -> void: if !is_level_allowed(level): emit_signal("log_event", false, level, origin, message, "") diff --git a/src/misc.gd b/src/misc.gd index dc9e120..b14988b 100644 --- a/src/misc.gd +++ b/src/misc.gd @@ -21,6 +21,19 @@ ## and generally make your life as a developer easier. extends CoreBaseModule +# Configuration +var config_stringify_show_type: bool +var config_stringify_color_range8: bool +var config_stringify_array: bool +var config_stringify_dictionary: bool + +# +++ module +++ +func _pull_config() -> void: + config_stringify_show_type = core.config.misc_stringify_show_type + config_stringify_color_range8 = core.config.misc_stringify_color_range8 + config_stringify_array = core.config.misc_stringify_array + config_stringify_dictionary = core.config.misc_stringify_dictionary + # +++ data type conversion +++ ## Converts a number of bytes into mebibytes.[br] ## [br] @@ -125,6 +138,114 @@ func stringarray_to_array(array: Array[String]) -> Array: func get_center(parent_size: Vector2, child_size: Vector2) -> Vector2: return Vector2(parent_size.x/2-child_size.x/2, parent_size.y/2-child_size.y/2) +## Makes variables as look correct inside strings.[br] +## Short examples:[br] +## [code]true[/code] -> [code]'true'[/code][br] +## [code]Vector2(69.064, PI)[/code] -> [code]'x=69.064 y=3.14159265358979'[/code][br] +## [code]"This is a test string"[/code] -> [code]'"This is a test string"'[/code][br] +## Full example:[br] +## [codeblock] +## Code: +## logger.diag(stringify_variables("Triggered %trigger% (pos=%position%, successful=%success%)", { "trigger": "shoot", "position": Vector2(5156.149, 581.69), "success": true })) +## +## Output: +## [16:44:35] [DIAG Test.gd] Triggered '"shoot"' (pos='x=5156.149 y=581.69', successful='true') +## [/codeblock] +func stringify_variables(template: String, variables: Dictionary, no_quotes: bool = false) -> String: + # To decrease allocations + var value + var type: String = "" + var replacement: String = "" + for placeholder in variables: + # Check key type + if typeof(placeholder) != TYPE_STRING: + logger.error("Invalid placeholder type '\"" + type_string(typeof(placeholder)) + "\", skipping") + continue + + # Check for correct type + value = variables[placeholder] + + match(typeof(value)): + # Primitives + Variant.Type.TYPE_NIL: replacement = "null" + Variant.Type.TYPE_BOOL: replacement = str(value) + Variant.Type.TYPE_INT: replacement = str(value) + Variant.Type.TYPE_FLOAT: replacement = str(value) + Variant.Type.TYPE_STRING: replacement = "\"" + value + "\"" + Variant.Type.TYPE_STRING_NAME: replacement = "\"" + value + "\"" + # Non-primitives + Variant.Type.TYPE_OBJECT: replacement = str(value) + Variant.Type.TYPE_COLOR: + if config_stringify_color_range8: replacement = "r=" + _sa(value.r8) + " g=" + _sa(value.g8) + " b=" + _sa(value.b8) + " a=" + _sa(value.a8) + else: replacement = "r=" + _sa(value.r) + " g=" + _sa(value.g) + " b=" + _sa(value.b) + " a=" + _sa(value.a) + Variant.Type.TYPE_RID: replacement = "id=" + _sa(value.get_id()) + " valid=" + _sa(value.is_valid()) + Variant.Type.TYPE_ARRAY: + if config_stringify_array: + if value.size() == 0: + replacement = "[]" + else: + replacement = "[ " + for item in value: + if replacement == "[ ": replacement += _sa(item) + else: replacement += ", " + _sa(item) + replacement += " ]" + else: replacement = str(value) + Variant.Type.TYPE_DICTIONARY: + if config_stringify_dictionary: + if value.size() == 0: replacement = "{}" + else: + replacement = "{ " + for key in value: + if replacement == "{ ": replacement += _sa(key) + ": " + _sa(value[key]) + else: replacement += ", " + _sa(key) + replacement += " }" + else: replacement = str(value) + # TODO: Packed Arrays + # Nodes & scripting + Variant.Type.TYPE_NODE_PATH: replacement = str(value) + Variant.Type.TYPE_CALLABLE: replacement = "valid=" + _sa(value.is_valid()) + " standard=" + _sa(value.is_standard()) + " object=" + _sa(value.get_object() ) + " method=" + value.get_method() + " args=" + _sa(value.get_bound_arguments()) + Variant.Type.TYPE_SIGNAL: replacement = "name=" + _sa(value.get_name()) + " object=" + _sa(value.get_object()) + # 2D + Variant.Type.TYPE_VECTOR2: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + Variant.Type.TYPE_VECTOR2I: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + Variant.Type.TYPE_RECT2: replacement = "size=" + _sa(value.size) + " pos=" + _sa(value.position) + " end=" + _sa(value.end) + Variant.Type.TYPE_RECT2I: replacement = "size=" + _sa(value.size) + " pos=" + _sa(value.position) + " end=" + _sa(value.end) + Variant.Type.TYPE_TRANSFORM2D: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " origin=" + _sa(value.origin) + # 3D + Variant.Type.TYPE_VECTOR3: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z) + Variant.Type.TYPE_VECTOR3I: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z) + Variant.Type.TYPE_PLANE: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z) + " d=" + _sa(value.d) + " normal=" + _sa(value.normal) + Variant.Type.TYPE_QUATERNION: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z) + " w=" + _sa(value.w) + Variant.Type.TYPE_AABB: replacement = "size=" + _sa(value.size) + " pos=" + _sa(value.position) + " end=" + _sa(value.end) + Variant.Type.TYPE_TRANSFORM3D: replacement = "basis=" + _sa(value.basis) + " origin=" + _sa(value.origin) + Variant.Type.TYPE_BASIS: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z) + Variant.Type.TYPE_PROJECTION: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z) + " w=" + _sa(value.w) + # 4D + Variant.Type.TYPE_VECTOR4: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z) + " w=" + _sa(value.w) + Variant.Type.TYPE_VECTOR4I: replacement = "x=" + _sa(value.x) + " y=" + _sa(value.y) + " z=" + _sa(value.z) + " w=" + _sa(value.w) + # etc + Variant.Type.TYPE_MAX: replacement = str(value) + _: + replacement = str(value) + type = "(unknown) " + + # Replace + if config_stringify_show_type and type == "": + match(typeof(value)): + Variant.Type.TYPE_NIL: type = "" + Variant.Type.TYPE_MAX: type = "(invalid) " + Variant.Type.TYPE_ARRAY: + if value.get_typed_builtin() != TYPE_NIL: + type = "(" + type_string(typeof(value)).to_lower() + "[" + type_string(typeof(value.get_typed_builtin())).to_lower() + "]) " + _: type = "(" + type_string(typeof(value)).to_lower() + ") " # something is causing almost everything to be displayed as a boolean, which is not true. i don't know what's the problem here however. + var quote: String = "'" if !no_quotes else "" + template = template.replace("%" + placeholder + "%", quote + type + replacement + quote) + return template + +# Makes calls shorter +func _sa(value) -> String: + return stringify_variables("%var%", { "var": value }, true) + ## Moved to [method Core.quit_safely]. ## @deprecated func quit_safely(exitcode: int = 0) -> void: await core.quit_safely(exitcode) diff --git a/src/sms.gd b/src/sms.gd index 26138b5..56d06cf 100644 --- a/src/sms.gd +++ b/src/sms.gd @@ -22,24 +22,14 @@ extends CoreBaseModule ## Used internally for adding, managing and removing scene collections. const scene_nodes: Array[String] = [ "debug", "cutscene", "menu", "main", "background" ] -## The 'debug' scene collection.[br] -## [b]Danger: [i]Don't modify this.[/i][/b] +# Scene collections var scenes_debug: Node = Node.new() -## The 'cutscene' scene collection.[br] -## [b]Danger: [i]Don't modify this.[/i][/b] var scenes_cutscene: Node = Node.new() -## The 'menu' scene collection.[br] -## [b]Danger: [i]Don't modify this.[/i][/b] var scenes_menu: Node = Node.new() -## The 'main' scene collection.[br] -## [b]Danger: [i]Don't modify this.[/i][/b] var scenes_main: Node = Node.new() -## The 'background' scene collection.[br] -## [b]Danger: [i]Don't modify this.[/i][/b] var scenes_background: Node = Node.new() -## A list of all loaded scenes[br] -## [b]Danger: [i]Don't modify this.[/i][/b] +# A list of all loaded scenes. var scenes: Dictionary = {} # +++ module +++ @@ -64,109 +54,109 @@ func _pull_config() -> void: # +++ scene management +++ ## Adds a scene to some scene collection. -func add_scene(sname: String, sclass: Node, type: CoreTypes.SceneType) -> bool: +func add_scene(scene_name: String, scene_class: Node, scene_type: CoreTypes.SceneType) -> bool: if core.config.headless: return false - loggeri.verb("Adding scene \"" + sname + "\" of type " + str(type)) - if exists(sname) != CoreTypes.SceneType.NONE: - loggeri.error("Scene with name \"" + sname + "\" already exists") + loggeri.verb("Adding scene \"" + scene_name + "\" of type " + str(scene_type)) + if exists(scene_name) != CoreTypes.SceneType.NONE: + loggeri.error("Scene with name \"" + scene_name + "\" already exists") return false - if typeof(sclass) != TYPE_OBJECT or !sclass.is_class("Node"): - loggeri.error("Scene class \"" + sname + "\" is not of type Node") + if typeof(scene_class) != TYPE_OBJECT or !scene_class.is_class("Node"): + loggeri.error("Scene class \"" + scene_name + "\" is not of type Node") return false - sclass.name = sname - match(type): - CoreTypes.SceneType.DEBUG: scenes_debug.add_child(sclass) - CoreTypes.SceneType.CUTSCENE: scenes_cutscene.add_child(sclass) - CoreTypes.SceneType.MENU: scenes_menu.add_child(sclass) - CoreTypes.SceneType.MAIN: scenes_main.add_child(sclass) - CoreTypes.SceneType.BACKGROUND: scenes_background.add_child(sclass) + scene_class.name = scene_name + match(scene_type): + CoreTypes.SceneType.DEBUG: scenes_debug.add_child(scene_class) + CoreTypes.SceneType.CUTSCENE: scenes_cutscene.add_child(scene_class) + CoreTypes.SceneType.MENU: scenes_menu.add_child(scene_class) + CoreTypes.SceneType.MAIN: scenes_main.add_child(scene_class) + CoreTypes.SceneType.BACKGROUND: scenes_background.add_child(scene_class) CoreTypes.SceneType.NONE: loggeri.error("CoreTypes.SceneType.NONE is not a valid scene type") return false - _: await loggeri.crash("Invalid SceneType " + str(type)) - scenes.merge({ sname: { "type": type, "class": sclass } }) + _: await loggeri.crash("Invalid SceneType " + str(scene_type)) + scenes.merge({ scene_name: { "type": scene_type, "class": scene_class } }) return true ## Removes a scene from some scene collection.[br] ## [b]Danger: [i]Don't set [code]force_remove[/code] to [code]true[/code], thanks![/i][/b] -func remove_scene(sname: String, force_remove: bool = false) -> bool: +func remove_scene(scene_name: String, force_remove: bool = false) -> bool: if core.config.headless and !force_remove: return false if force_remove: await loggeri.crash("force_remove = true is not allowed") - loggeri.verb("Removing scene \"" + sname + "\"") - match(exists(sname)): + loggeri.verb("Removing scene \"" + scene_name + "\"") + match(exists(scene_name)): CoreTypes.SceneType.DEBUG: - scenes_debug.remove_child(scenes[sname]["class"]) - scenes[sname]["class"].queue_free() + scenes_debug.remove_child(scenes[scene_name]["class"]) + scenes[scene_name]["class"].queue_free() CoreTypes.SceneType.CUTSCENE: - scenes_cutscene.remove_child(scenes[sname]["class"]) - scenes[sname]["class"].queue_free() + scenes_cutscene.remove_child(scenes[scene_name]["class"]) + scenes[scene_name]["class"].queue_free() CoreTypes.SceneType.MENU: - scenes_menu.remove_child(scenes[sname]["class"]) - scenes[sname]["class"].queue_free() + scenes_menu.remove_child(scenes[scene_name]["class"]) + scenes[scene_name]["class"].queue_free() CoreTypes.SceneType.MAIN: - scenes_main.remove_child(scenes[sname]["class"]) - scenes[sname]["class"].queue_free() + scenes_main.remove_child(scenes[scene_name]["class"]) + scenes[scene_name]["class"].queue_free() CoreTypes.SceneType.BACKGROUND: - scenes_background.remove_child(scenes[sname]["class"]) - scenes[sname]["class"].queue_free() + scenes_background.remove_child(scenes[scene_name]["class"]) + scenes[scene_name]["class"].queue_free() CoreTypes.SceneType.NONE: - loggeri.error("Scene \"" + sname + "\" does not exist") + loggeri.error("Scene \"" + scene_name + "\" does not exist") return false - _: await loggeri.crash("Invalid SceneType " + str(exists(sname))) - scenes.erase(sname) + _: await loggeri.crash("Invalid SceneType " + str(exists(scene_name))) + scenes.erase(scene_name) return true # +++ getters +++ ## Returns a scene from some scene collection.[br] ## [br] ## Returns [code]null[/code] if no scene with that name was found. -func get_scene(sname: String) -> Node: +func get_scene(scene_name: String) -> Node: if core.config.headless: return null - match(exists(sname)): - CoreTypes.SceneType.DEBUG: return scenes[sname]["class"] - CoreTypes.SceneType.CUTSCENE: return scenes[sname]["class"] - CoreTypes.SceneType.MENU: return scenes[sname]["class"] - CoreTypes.SceneType.MAIN: return scenes[sname]["class"] - CoreTypes.SceneType.BACKGROUND: return scenes[sname]["class"] - CoreTypes.SceneType.NONE: loggeri.error("Scene \"" + sname + "\" does not exist") - _: await loggeri.crash("Invalid SceneType " + str(exists(sname))) + match(exists(scene_name)): + CoreTypes.SceneType.DEBUG: return scenes[scene_name]["class"] + CoreTypes.SceneType.CUTSCENE: return scenes[scene_name]["class"] + CoreTypes.SceneType.MENU: return scenes[scene_name]["class"] + CoreTypes.SceneType.MAIN: return scenes[scene_name]["class"] + CoreTypes.SceneType.BACKGROUND: return scenes[scene_name]["class"] + CoreTypes.SceneType.NONE: loggeri.error("Scene \"" + scene_name + "\" does not exist") + _: await loggeri.crash("Invalid SceneType " + str(exists(scene_name))) return null ## Returns a scene collection node.[br] ## Useful if you want to change a child's index.[br] ## [b]Danger: [i]Don't change any properties of the scene collection or free it, otherwise you may cause breakage.[/i][/b] -func get_scene_collection(type: CoreTypes.SceneType) -> Node: +func get_scene_collection(scene_type: CoreTypes.SceneType) -> Node: if core.config.headless: return null - match(type): + match(scene_type): CoreTypes.SceneType.DEBUG: return scenes_debug CoreTypes.SceneType.CUTSCENE: return scenes_cutscene CoreTypes.SceneType.MENU: return scenes_menu CoreTypes.SceneType.MAIN: return scenes_main CoreTypes.SceneType.BACKGROUND: return scenes_background CoreTypes.SceneType.NONE: loggeri.error("No scene collection was found for CoreTypes.SceneType.NONE") - _: await loggeri.crash("Invalid SceneType " + str(type)) + _: await loggeri.crash("Invalid SceneType " + str(scene_type)) return null ## Returns a list of all loaded scenes in some scene collection. -func get_scene_collection_list(type: CoreTypes.SceneType) -> Array[Node]: +func get_scene_collection_list(scene_type: CoreTypes.SceneType) -> Array[Node]: var list: Array[Node] = [] for scene in scenes: - if scenes[scene]["type"] == type: + if scenes[scene]["type"] == scene_type: list.append(scenes[scene]["class"]) return list ## Returns the number of loaded scenes in some scene collection. -func get_scene_collection_count(type: CoreTypes.SceneType) -> int: +func get_scene_collection_count(scene_type: CoreTypes.SceneType) -> int: var amount: int = 0 for scene in scenes: - if scenes[scene]["type"] == type: + if scenes[scene]["type"] == scene_type: amount += 1 return amount ## Returns the scene collection a scene is loaded in.[br] ## [br] ## [enum CoreTypes.SceneType][code].NONE[/code] if no scene with that name was found. -func exists(sname: String) -> CoreTypes.SceneType: +func exists(scene_name: String) -> CoreTypes.SceneType: for scene in scenes: - if scene == sname: return scenes[scene]["type"] + if scene == scene_name: return scenes[scene]["type"] return CoreTypes.SceneType.NONE diff --git a/src/storage.gd b/src/storage.gd index 391de50..9583b2b 100644 --- a/src/storage.gd +++ b/src/storage.gd @@ -23,15 +23,13 @@ extends CoreBaseModule ## Indicates if a storage file is currently open.[br] ## [b]Danger: [i]Don't modify this.[/i][/b] var is_open: bool = false -## The parsed data inside the storage file.[br] -## [b]Danger: [i]Don't modify this.[/i][/b] +# The parsed data inside the storage file. var storage: Dictionary = {} -## The location of the storage file.[br] -## [b]Danger: [i]Don't modify this.[/i][/b] +# The location of the storage file. var storage_location: String = "" # +++ file management +++ -## Opens a storage file into memory. +## Opens a storage file and loads it into memory. func open_storage(location: String, create_new: bool = true, sanity_check: bool = true, fail_on_sanity_check: bool = false) -> bool: if is_open: loggeri.error("Failed to open storage: A storage file is already open")