2
0
Fork 0

Update to f5e50b1f6b3d5e9f5d4c74fd32ac536e46143804

This commit is contained in:
JeremyStar™ 2024-04-17 16:37:18 +02:00
parent c165939267
commit 99efd65300
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
7 changed files with 283 additions and 108 deletions

View file

@ -45,6 +45,18 @@ class_name CoreConfiguration
@export var logui_background_color: Color @export var logui_background_color: Color
## What font size the graphical log should have. ## What font size the graphical log should have.
@export var logui_font_size: int @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") @export_category("Easy Request Maker")
## Determines how unsecure requests should be handled. ## Determines how unsecure requests should be handled.
@export var erm_unsecure_requests: CoreTypes.BlockadeLevel @export var erm_unsecure_requests: CoreTypes.BlockadeLevel
@ -63,9 +75,17 @@ func _init() -> void:
logger_format = "%color%[%time%] [%level% %origin%] %message%" logger_format = "%color%[%time%] [%level% %origin%] %message%"
logger_newlines_override = true logger_newlines_override = true
logger_newlines_sizelimit = 40 logger_newlines_sizelimit = 40
# Log UI # Log UI
logui_enabled = true logui_enabled = true
logui_background_color = Color.BLACK # To disable the background, use Color.TRANSPARENT logui_background_color = Color.BLACK # To disable the background, use Color.TRANSPARENT
logui_font_size = 14 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 # Easy Request Maker
erm_unsecure_requests = CoreTypes.BlockadeLevel.BLOCK erm_unsecure_requests = CoreTypes.BlockadeLevel.BLOCK

View file

@ -57,18 +57,16 @@ var storage: CoreBaseModule
## Stores the path to CORE's installation directory.[br] ## Stores the path to CORE's installation directory.[br]
## [b]Danger: [i]Don't modify this.[/i][/b] ## [b]Danger: [i]Don't modify this.[/i][/b]
var basepath: String var basepath: String
## Contains a list of all loaded custom modules.[br] # Contains a list of all registered cleanup hooks.
## [b]Danger: [i]Don't modify this.[/i][/b] var cleanup_hooks: Dictionary = {}
# Contains a list of all loaded custom modules.
var custom_modules: Dictionary = {} var custom_modules: Dictionary = {}
## Contains the node holding all custom modules as children.[br] # Contains the node holding all custom modules as children.
## [b]Danger: [i]Don't modify this.[/i][/b]
var custom_modules_node: Node var custom_modules_node: Node
## The CORE Object's logger instance. # The CORE Object's logger instance.
## [b]Danger: [i]Don't modify this.[/i][/b]
var loggeri: CoreLoggerInstance var loggeri: CoreLoggerInstance
# +++ initialization +++ # +++ 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: func _init(new_config: CoreConfiguration = CoreConfiguration.new()) -> void:
name = "CORE" name = "CORE"
if !check_godot_version(): return if !check_godot_version(): return
@ -79,8 +77,6 @@ func _init(new_config: CoreConfiguration = CoreConfiguration.new()) -> void:
apply_configuration() apply_configuration()
initialize_scheduler() 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: func _ready() -> void:
inject_modules() inject_modules()
custom_modules_node.name = "Custom Modules" custom_modules_node.name = "Custom Modules"
@ -89,8 +85,7 @@ func _ready() -> void:
add_child(scheduler) add_child(scheduler)
get_tree().auto_accept_quit = false get_tree().auto_accept_quit = false
## Initializes all built-in modules during the preinitialization phase.[br] # Initializes all built-in modules during the preinitialization phase.
## [b]Danger: [i]Don't call this.[/i][/b]
func initialize_modules() -> void: func initialize_modules() -> void:
for module in modules: for module in modules:
set(module, CoreBaseModule.new()) 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).loggeri = logger.get_instance(basepath.replace("res://", "") + "src/" + module + ".gd", get(module))
get(module)._initialize() get(module)._initialize()
## Injects CORE's builtin modules into the SceneTree.[br] # Injects CORE's builtin modules into the SceneTree.
## [b]Danger: [i]Don't call this.[/i][/b]
func inject_modules() -> void: for module in modules: add_child(get(module)) func inject_modules() -> void: for module in modules: add_child(get(module))
## Initializes the framework scheduler. # Initializes the framework scheduler.
## [b]Danger: [i]Don't call this.[/i][/b]
func initialize_scheduler() -> void: func initialize_scheduler() -> void:
scheduler = Timer.new() scheduler = Timer.new()
scheduler.name = "Scheduler" 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: loggeri.verb("Overrode configuration (development mode)")
if initialized: apply_configuration() if initialized: apply_configuration()
## Applies the a configuration.[br] # Applies a new configuration.
## [b]Danger: [i]Don't call this.[/i][/b]
func apply_configuration() -> void: func apply_configuration() -> void:
if loggeri != null: loggeri.verb("Applying configuration") 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!") 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): if !custom_modules.has(module_name):
loggeri.error("Unregistering module failed: A custom module with the name \"" + module_name + "\" does not exist.") loggeri.error("Unregistering module failed: A custom module with the name \"" + module_name + "\" does not exist.")
return return
var module: Node = get_custom_module(module_name) var module: Node = custom_modules[module_name]
await module._cleanup() await module._cleanup()
module.loggeri.queue_free() module.loggeri.queue_free()
custom_modules_node.remove_child(module) custom_modules_node.remove_child(module)
@ -226,23 +218,80 @@ func get_custom_module(module_name: String) -> CoreBaseModule:
return null return null
return custom_modules[module_name] return custom_modules[module_name]
# +++ etc ++ # +++ cleanup ++
## Makes sure that CORE does not leak memory on shutdown/unload.[br] ## 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: func cleanup() -> void:
loggeri.info("Cleaning up") 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) remove_child(custom_modules_node)
custom_modules_node.queue_free() custom_modules_node.queue_free()
loggeri.verb("Unloading built-in modules")
var modules_reverse: Array[String] = modules.duplicate() var modules_reverse: Array[String] = modules.duplicate()
modules_reverse.reverse() modules_reverse.reverse()
for module in modules_reverse: for module in modules_reverse:
await get(module)._cleanup() await get(module)._cleanup()
get(module).loggeri.queue_free()
get(module).queue_free() get(module).queue_free()
print("Freeing configuration")
config.queue_free() config.queue_free()
await get_tree().process_frame
print("Freeing")
queue_free() 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. ## Returns if the framework is in development mode.
func is_devmode() -> bool: func is_devmode() -> bool:
return config.development return config.development
@ -299,8 +348,7 @@ func get_version_semantic() -> Array[int]:
CoreTypes.VersionType.ALPHA: version_type_int = 0 CoreTypes.VersionType.ALPHA: version_type_int = 0
return [version_version, version_type_int, version_typerelease] return [version_version, version_type_int, version_typerelease]
## Determines CORE's installation/base path.[br] # Determines CORE's installation/base path.
## [b]Danger: [i]Don't call this.[/i][/b]
func determine_basepath() -> bool: func determine_basepath() -> bool:
if FileAccess.file_exists("res://.corebasepath"): if FileAccess.file_exists("res://.corebasepath"):
basepath = "res://" basepath = "res://"
@ -313,7 +361,6 @@ func determine_basepath() -> bool:
return false return false
return true return true
# Checks Godot's version
## Checks compatibility with the running version. ## Checks compatibility with the running version.
func check_godot_version() -> bool: func check_godot_version() -> bool:
var version: Dictionary = Engine.get_version_info() var version: Dictionary = Engine.get_version_info()
@ -343,6 +390,7 @@ func quit_safely(exitcode: int = 0) -> void:
await cleanup() await cleanup()
get_tree().quit(exitcode) get_tree().quit(exitcode)
# Just ignore this.
func _notification(what) -> void: func _notification(what) -> void:
match(what): match(what):
NOTIFICATION_WM_CLOSE_REQUEST: NOTIFICATION_WM_CLOSE_REQUEST:

View file

@ -18,14 +18,11 @@
## Allows for awaited, batched and oneline requests. ## Allows for awaited, batched and oneline requests.
extends CoreBaseModule extends CoreBaseModule
## Contains a list of all queued downloads.[br] # Contains a list of all queued downloads.
## [b]Danger: [i]Don't modify this[/i][/b].
var list_queue: Dictionary = {} var list_queue: Dictionary = {}
## Contains a list of all active downloads.[br] # Contains a list of all active downloads.
## [b]Danger: [i]Don't modify this[/i][/b].
var list_active: Dictionary = {} var list_active: Dictionary = {}
## Contains a liust of all completed downloads.[br] # Contains a liust of all completed downloads.
## [b]Danger: [i]Don't modify this[/i][/b].
var list_complete: Dictionary = {} var list_complete: Dictionary = {}
## Determines how unsecure requests should be handled. ## 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) list_complete.erase(id)
return dldata 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: 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) var id: int = create_request(url, method, headers, data)
start_request(id, parse_utf8) start_request(id, parse_utf8)
@ -116,8 +113,7 @@ func _batch_awaited_request(url: String, parse_utf8: bool, method: HTTPClient.Me
return id return id
# +++ internal +++ # +++ internal +++
## Returns a new download id.[br] # Returns a new download id.
## [b]Danger: [i]Don't call this.[/i][/b]
func generate_id() -> int: func generate_id() -> int:
var id = randi() var id = randi()
if list_queue.has(id) or list_active.has(id): if list_queue.has(id) or list_active.has(id):

View file

@ -23,9 +23,7 @@ extends CoreBaseModule
signal log_event signal log_event
## Keeps track of all logger instances. # Keeps track of all logger instances. Unused instances will be cleaned periodically by CORE's scheduler.
## Unused instances will be cleaned periodically.
## [b]Danger: [i]Don't modify this.[/i][/b]
var instances: Array[CoreLoggerInstance] = [] var instances: Array[CoreLoggerInstance] = []
## Used to determine if running in verbose/command line mode.[br] ## Used to determine if running in verbose/command line mode.[br]
@ -46,15 +44,20 @@ var config_newlines_sizelimit: int
# +++ module +++ # +++ module +++
func _cleanup() -> void: func _cleanup() -> void:
_schedule() for instance in instances:
await get_tree().process_frame if is_instance_valid(instance):
loggeri.diag("Removing instance '" + instance.name + "'")
instance.queue_free()
func _schedule() -> void: func _schedule() -> void:
var instances_remove_enty: Array[CoreLoggerInstance] = []
for instance in instances: for instance in instances:
if !is_instance_valid(instance): continue if !is_instance_valid(instance): continue
if !is_instance_valid(instance.parent): if !is_instance_valid(instance.parent):
loggeri.diag("Removing instance '" + instance.name + "'") loggeri.diag("Removing instance '" + instance.name + "'")
instance.queue_free() instance.queue_free()
instances_remove_enty.append(instance)
for instance in instances_remove_enty:
instances.remove_at(instances.find(instance)) instances.remove_at(instances.find(instance))
func _pull_config() -> void: func _pull_config() -> void:
@ -65,8 +68,7 @@ func _pull_config() -> void:
config_newlines_sizelimit = core.config.logger_newlines_sizelimit config_newlines_sizelimit = core.config.logger_newlines_sizelimit
# +++ logging +++ # +++ logging +++
## The main logging function that does the heavy lifting.[br] # The main logging function that does the heavy lifting.
## [b]Danger: [i]Don't call this.[/i][/b]
func _log(level: CoreTypes.LoggerLevel, origin: String, message: String) -> void: func _log(level: CoreTypes.LoggerLevel, origin: String, message: String) -> void:
if !is_level_allowed(level): if !is_level_allowed(level):
emit_signal("log_event", false, level, origin, message, "") emit_signal("log_event", false, level, origin, message, "")

View file

@ -21,6 +21,19 @@
## and generally make your life as a developer easier. ## and generally make your life as a developer easier.
extends CoreBaseModule 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 +++ # +++ data type conversion +++
## Converts a number of bytes into mebibytes.[br] ## Converts a number of bytes into mebibytes.[br]
## [br] ## [br]
@ -125,6 +138,114 @@ func stringarray_to_array(array: Array[String]) -> Array:
func get_center(parent_size: Vector2, child_size: Vector2) -> Vector2: 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) 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]. ## Moved to [method Core.quit_safely].
## @deprecated ## @deprecated
func quit_safely(exitcode: int = 0) -> void: await core.quit_safely(exitcode) func quit_safely(exitcode: int = 0) -> void: await core.quit_safely(exitcode)

View file

@ -22,24 +22,14 @@ extends CoreBaseModule
## Used internally for adding, managing and removing scene collections. ## Used internally for adding, managing and removing scene collections.
const scene_nodes: Array[String] = [ "debug", "cutscene", "menu", "main", "background" ] const scene_nodes: Array[String] = [ "debug", "cutscene", "menu", "main", "background" ]
## The 'debug' scene collection.[br] # Scene collections
## [b]Danger: [i]Don't modify this.[/i][/b]
var scenes_debug: Node = Node.new() 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() 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() 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() 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() var scenes_background: Node = Node.new()
## A list of all loaded scenes[br] # A list of all loaded scenes.
## [b]Danger: [i]Don't modify this.[/i][/b]
var scenes: Dictionary = {} var scenes: Dictionary = {}
# +++ module +++ # +++ module +++
@ -64,109 +54,109 @@ func _pull_config() -> void:
# +++ scene management +++ # +++ scene management +++
## Adds a scene to some scene collection. ## 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 if core.config.headless: return false
loggeri.verb("Adding scene \"" + sname + "\" of type " + str(type)) loggeri.verb("Adding scene \"" + scene_name + "\" of type " + str(scene_type))
if exists(sname) != CoreTypes.SceneType.NONE: if exists(scene_name) != CoreTypes.SceneType.NONE:
loggeri.error("Scene with name \"" + sname + "\" already exists") loggeri.error("Scene with name \"" + scene_name + "\" already exists")
return false return false
if typeof(sclass) != TYPE_OBJECT or !sclass.is_class("Node"): if typeof(scene_class) != TYPE_OBJECT or !scene_class.is_class("Node"):
loggeri.error("Scene class \"" + sname + "\" is not of type Node") loggeri.error("Scene class \"" + scene_name + "\" is not of type Node")
return false return false
sclass.name = sname scene_class.name = scene_name
match(type): match(scene_type):
CoreTypes.SceneType.DEBUG: scenes_debug.add_child(sclass) CoreTypes.SceneType.DEBUG: scenes_debug.add_child(scene_class)
CoreTypes.SceneType.CUTSCENE: scenes_cutscene.add_child(sclass) CoreTypes.SceneType.CUTSCENE: scenes_cutscene.add_child(scene_class)
CoreTypes.SceneType.MENU: scenes_menu.add_child(sclass) CoreTypes.SceneType.MENU: scenes_menu.add_child(scene_class)
CoreTypes.SceneType.MAIN: scenes_main.add_child(sclass) CoreTypes.SceneType.MAIN: scenes_main.add_child(scene_class)
CoreTypes.SceneType.BACKGROUND: scenes_background.add_child(sclass) CoreTypes.SceneType.BACKGROUND: scenes_background.add_child(scene_class)
CoreTypes.SceneType.NONE: CoreTypes.SceneType.NONE:
loggeri.error("CoreTypes.SceneType.NONE is not a valid scene type") loggeri.error("CoreTypes.SceneType.NONE is not a valid scene type")
return false return false
_: await loggeri.crash("Invalid SceneType " + str(type)) _: await loggeri.crash("Invalid SceneType " + str(scene_type))
scenes.merge({ sname: { "type": type, "class": sclass } }) scenes.merge({ scene_name: { "type": scene_type, "class": scene_class } })
return true return true
## Removes a scene from some scene collection.[br] ## 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] ## [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 core.config.headless and !force_remove: return false
if force_remove: await loggeri.crash("force_remove = true is not allowed") if force_remove: await loggeri.crash("force_remove = true is not allowed")
loggeri.verb("Removing scene \"" + sname + "\"") loggeri.verb("Removing scene \"" + scene_name + "\"")
match(exists(sname)): match(exists(scene_name)):
CoreTypes.SceneType.DEBUG: CoreTypes.SceneType.DEBUG:
scenes_debug.remove_child(scenes[sname]["class"]) scenes_debug.remove_child(scenes[scene_name]["class"])
scenes[sname]["class"].queue_free() scenes[scene_name]["class"].queue_free()
CoreTypes.SceneType.CUTSCENE: CoreTypes.SceneType.CUTSCENE:
scenes_cutscene.remove_child(scenes[sname]["class"]) scenes_cutscene.remove_child(scenes[scene_name]["class"])
scenes[sname]["class"].queue_free() scenes[scene_name]["class"].queue_free()
CoreTypes.SceneType.MENU: CoreTypes.SceneType.MENU:
scenes_menu.remove_child(scenes[sname]["class"]) scenes_menu.remove_child(scenes[scene_name]["class"])
scenes[sname]["class"].queue_free() scenes[scene_name]["class"].queue_free()
CoreTypes.SceneType.MAIN: CoreTypes.SceneType.MAIN:
scenes_main.remove_child(scenes[sname]["class"]) scenes_main.remove_child(scenes[scene_name]["class"])
scenes[sname]["class"].queue_free() scenes[scene_name]["class"].queue_free()
CoreTypes.SceneType.BACKGROUND: CoreTypes.SceneType.BACKGROUND:
scenes_background.remove_child(scenes[sname]["class"]) scenes_background.remove_child(scenes[scene_name]["class"])
scenes[sname]["class"].queue_free() scenes[scene_name]["class"].queue_free()
CoreTypes.SceneType.NONE: CoreTypes.SceneType.NONE:
loggeri.error("Scene \"" + sname + "\" does not exist") loggeri.error("Scene \"" + scene_name + "\" does not exist")
return false return false
_: await loggeri.crash("Invalid SceneType " + str(exists(sname))) _: await loggeri.crash("Invalid SceneType " + str(exists(scene_name)))
scenes.erase(sname) scenes.erase(scene_name)
return true return true
# +++ getters +++ # +++ getters +++
## Returns a scene from some scene collection.[br] ## Returns a scene from some scene collection.[br]
## [br] ## [br]
## Returns [code]null[/code] if no scene with that name was found. ## 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 if core.config.headless: return null
match(exists(sname)): match(exists(scene_name)):
CoreTypes.SceneType.DEBUG: return scenes[sname]["class"] CoreTypes.SceneType.DEBUG: return scenes[scene_name]["class"]
CoreTypes.SceneType.CUTSCENE: return scenes[sname]["class"] CoreTypes.SceneType.CUTSCENE: return scenes[scene_name]["class"]
CoreTypes.SceneType.MENU: return scenes[sname]["class"] CoreTypes.SceneType.MENU: return scenes[scene_name]["class"]
CoreTypes.SceneType.MAIN: return scenes[sname]["class"] CoreTypes.SceneType.MAIN: return scenes[scene_name]["class"]
CoreTypes.SceneType.BACKGROUND: return scenes[sname]["class"] CoreTypes.SceneType.BACKGROUND: return scenes[scene_name]["class"]
CoreTypes.SceneType.NONE: loggeri.error("Scene \"" + sname + "\" does not exist") CoreTypes.SceneType.NONE: loggeri.error("Scene \"" + scene_name + "\" does not exist")
_: await loggeri.crash("Invalid SceneType " + str(exists(sname))) _: await loggeri.crash("Invalid SceneType " + str(exists(scene_name)))
return null return null
## Returns a scene collection node.[br] ## Returns a scene collection node.[br]
## Useful if you want to change a child's index.[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] ## [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 if core.config.headless: return null
match(type): match(scene_type):
CoreTypes.SceneType.DEBUG: return scenes_debug CoreTypes.SceneType.DEBUG: return scenes_debug
CoreTypes.SceneType.CUTSCENE: return scenes_cutscene CoreTypes.SceneType.CUTSCENE: return scenes_cutscene
CoreTypes.SceneType.MENU: return scenes_menu CoreTypes.SceneType.MENU: return scenes_menu
CoreTypes.SceneType.MAIN: return scenes_main CoreTypes.SceneType.MAIN: return scenes_main
CoreTypes.SceneType.BACKGROUND: return scenes_background CoreTypes.SceneType.BACKGROUND: return scenes_background
CoreTypes.SceneType.NONE: loggeri.error("No scene collection was found for CoreTypes.SceneType.NONE") 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 return null
## Returns a list of all loaded scenes in some scene collection. ## 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] = [] var list: Array[Node] = []
for scene in scenes: for scene in scenes:
if scenes[scene]["type"] == type: if scenes[scene]["type"] == scene_type:
list.append(scenes[scene]["class"]) list.append(scenes[scene]["class"])
return list return list
## Returns the number of loaded scenes in some scene collection. ## 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 var amount: int = 0
for scene in scenes: for scene in scenes:
if scenes[scene]["type"] == type: if scenes[scene]["type"] == scene_type:
amount += 1 amount += 1
return amount return amount
## Returns the scene collection a scene is loaded in.[br] ## Returns the scene collection a scene is loaded in.[br]
## [br] ## [br]
## [enum CoreTypes.SceneType][code].NONE[/code] if no scene with that name was found. ## [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: for scene in scenes:
if scene == sname: return scenes[scene]["type"] if scene == scene_name: return scenes[scene]["type"]
return CoreTypes.SceneType.NONE return CoreTypes.SceneType.NONE

View file

@ -23,15 +23,13 @@ extends CoreBaseModule
## Indicates if a storage file is currently open.[br] ## Indicates if a storage file is currently open.[br]
## [b]Danger: [i]Don't modify this.[/i][/b] ## [b]Danger: [i]Don't modify this.[/i][/b]
var is_open: bool = false var is_open: bool = false
## The parsed data inside the storage file.[br] # The parsed data inside the storage file.
## [b]Danger: [i]Don't modify this.[/i][/b]
var storage: Dictionary = {} var storage: Dictionary = {}
## The location of the storage file.[br] # The location of the storage file.
## [b]Danger: [i]Don't modify this.[/i][/b]
var storage_location: String = "" var storage_location: String = ""
# +++ file management +++ # +++ 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: func open_storage(location: String, create_new: bool = true, sanity_check: bool = true, fail_on_sanity_check: bool = false) -> bool:
if is_open: if is_open:
loggeri.error("Failed to open storage: A storage file is already open") loggeri.error("Failed to open storage: A storage file is already open")