Update module logging and update many log calls

This commit firstly removes the 'logger' variable in CoreBaseModule, secondly renames 'loggeri' to 'logger' in CoreBaseModule, effectively replacing it, and thirdly it forces using 'stringify_variables' onto all log calls.
This commit is contained in:
JeremyStar™ 2024-04-25 20:20:34 +02:00
parent 53981c55f9
commit acc305d3db
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
8 changed files with 98 additions and 93 deletions

View file

@ -24,10 +24,8 @@ class_name CoreBaseModule
## Contains a reference to the CORE Object. ## Contains a reference to the CORE Object.
var core: Core var core: Core
## Set to CORE's logger implementation. ## Set to a [class CoreLoggerInstance] with the path you supplied to [method Core.register_custom_module].
@onready var logger: CoreBaseModule = core.logger var logger: CoreLoggerInstance
## Set to a [class CoreLoggerInstance] with the path you supplied to [method Core.register_custom_module]. You should use this over [code]logger[/code].
var loggeri: CoreLoggerInstance
## Marks a module as fully initialized and ready. **Don't forget to set this!** ## Marks a module as fully initialized and ready. **Don't forget to set this!**
var initialized: bool = false var initialized: bool = false

View file

@ -119,7 +119,7 @@ func initialize_modules() -> void:
get(module).name = module get(module).name = module
get(module).set_script(load(basepath + "src/" + module + ".gd")) get(module).set_script(load(basepath + "src/" + module + ".gd"))
get(module).core = self get(module).core = self
get(module).loggeri = logger.get_instance(basepath.replace("res://", "") + "src/" + module + ".gd", get(module)) get(module).logger = 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. # Injects CORE's builtin modules into the SceneTree.
@ -148,8 +148,8 @@ func initialize_scheduler() -> void:
## [i][b]Not calling this function during startup may lead to runtime issues.[/b][/i] ## [i][b]Not calling this function during startup may lead to runtime issues.[/b][/i]
func complete_init() -> void: func complete_init() -> void:
var inittime: int = Time.get_ticks_msec() var inittime: int = Time.get_ticks_msec()
var modsinit_builtin: Array[String] = ["workaround"] var modsinit_builtin: Array[String] = [ "workaround" ]
var modsinit_custom: Array[String] = ["workaround"] var modsinit_custom: Array[String] = [ "workaround" ]
while modsinit_builtin.size() != 0 and modsinit_custom.size() != 0: while modsinit_builtin.size() != 0 and modsinit_custom.size() != 0:
# Clear arrays # Clear arrays
@ -228,13 +228,13 @@ func register_custom_module(module_name: String, module_origin: String, module_c
loggeri.error("Registering module failed: Custom module support is disabled.") loggeri.error("Registering module failed: Custom module support is disabled.")
return false return false
if custom_modules.has(module_name): if custom_modules.has(module_name):
loggeri.error("Registering module failed: A custom module with the name \"" + module_name + "\" already exists.") loggeri.error(stringify_variables("Registering module failed: A custom module with the name %name% already exists.", { "name": module_name }))
return false return false
loggeri.diag("Updating variables") loggeri.diag("Updating variables")
module_class.name = module_name module_class.name = module_name
module_class.core = self module_class.core = self
module_class.loggeri = logger.get_instance(module_origin, module_class) module_class.loggeri = logger.get_instance(module_origin, module_class)
module_class.loggeri.framework = true module_class.logger.framework = true
loggeri.diag("Adding module to SceneTree") loggeri.diag("Adding module to SceneTree")
custom_modules_node.add_child(module_class) custom_modules_node.add_child(module_class)
loggeri.diag("Merging module with custom_modules") loggeri.diag("Merging module with custom_modules")
@ -249,11 +249,11 @@ func register_custom_module(module_name: String, module_origin: String, module_c
func unregister_custom_module(module_name: String) -> void: func unregister_custom_module(module_name: String) -> void:
loggeri.verb("Unregistering custom module \"" + module_name + "\"") loggeri.verb("Unregistering custom module \"" + module_name + "\"")
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(stringify_variables("Unregistering module failed: A custom module with the name %name% does not exist.", { "name": module_name }))
return return
var module: Node = custom_modules[module_name] var module: Node = custom_modules[module_name]
await module._cleanup() await module._cleanup()
module.loggeri.queue_free() module.logger.queue_free()
custom_modules_node.remove_child(module) custom_modules_node.remove_child(module)
custom_modules.erase(module_name) custom_modules.erase(module_name)
module.queue_free() module.queue_free()
@ -263,7 +263,7 @@ func unregister_custom_module(module_name: String) -> void:
func get_custom_module(module_name: String) -> CoreBaseModule: func get_custom_module(module_name: String) -> CoreBaseModule:
loggeri.diag("Getting custom module \"" + module_name + "\"") loggeri.diag("Getting custom module \"" + module_name + "\"")
if !custom_modules.has(module_name): if !custom_modules.has(module_name):
loggeri.error("Getting module failed: A custom module with the name \"" + module_name + "\" does not exist.") loggeri.error(stringify_variables("Getting module failed: A custom module with the name %name% does not exist.", { "name": module_name }))
return null return null
return custom_modules[module_name] return custom_modules[module_name]
@ -276,7 +276,7 @@ func cleanup() -> void:
loggeri.verb("Calling cleanup hooks") loggeri.verb("Calling cleanup hooks")
for hook in cleanup_hooks: for hook in cleanup_hooks:
if !cleanup_hooks[hook].is_valid(): if !cleanup_hooks[hook].is_valid():
loggeri.error("Cleanup hook #" + str(hook) + " is invalid") loggeri.error(stringify_variables("Cleanup hook %id% is invalid", { "id": hook }))
else: else:
loggeri.diag("Calling cleanup hook #" + str(hook)) loggeri.diag("Calling cleanup hook #" + str(hook))
await cleanup_hooks[hook].call() await cleanup_hooks[hook].call()
@ -302,10 +302,10 @@ func cleanup() -> void:
func _generate_hook_id() -> int: func _generate_hook_id() -> int:
var id = randi() var id = randi()
if cleanup_hooks.has(id): if cleanup_hooks.has(id):
loggeri.warn("New cleanup hook id #" + str(id) + " is already taken") loggeri.warn(stringify_variables("New cleanup hook id %id% is already taken", { "id": id }))
return _generate_hook_id() return _generate_hook_id()
elif id == -1: elif id == -1:
loggeri.warn("Invalid cleanup hook id '-1'") loggeri.warn(stringify_variables("Invalid cleanup hook id %id%", { "id": id }))
return _generate_hook_id() return _generate_hook_id()
return id return id
@ -324,9 +324,9 @@ func register_cleanup_hook(callable: Callable) -> int:
## Unregisters a cleanup hook by it's id. ## Unregisters a cleanup hook by it's id.
func unregister_cleanup_hook_by_id(id: int) -> bool: func unregister_cleanup_hook_by_id(id: int) -> bool:
if !cleanup_hooks.has(id): if !cleanup_hooks.has(id):
loggeri.error("Could not remove cleanup hook (id): Hook #" + str(id) + " does not exist") loggeri.error(stringify_variables("Could not remove cleanup hook (id): Hook %id% does not exist", { "id": id }))
return false return false
loggeri.verb("Removed cleanup hook #" + str(id) + " (id)") loggeri.verb(stringify_variables("Removed cleanup hook %id%", { "id": id }))
cleanup_hooks.erase(id) cleanup_hooks.erase(id)
return true return true
@ -336,9 +336,9 @@ func unregister_cleanup_hook_by_ref(callable: Callable) -> bool:
if id == null: if id == null:
loggeri.error("Could not remove cleanup hook (ref): Could not find a matching hook") loggeri.error("Could not remove cleanup hook (ref): Could not find a matching hook")
return false 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) + "')") if typeof(id) != TYPE_INT: await loggeri.crash(stringify_variables("Could not remove cleanup hook (ref): find_key did not return an integer (returned %id%)", { "id": id }))
loggeri.verb("Removed cleanup hook #" + str(id) + " (ref)")
cleanup_hooks.erase(id) cleanup_hooks.erase(id)
loggeri.verb(stringify_variables("Removed cleanup hook %id% (ref)", { "id": id }))
return true return true
# +++ etc +++ # +++ etc +++
@ -455,8 +455,13 @@ func quit_safely(exitcode: int = 0) -> void:
await cleanup() await cleanup()
get_tree().quit(exitcode) get_tree().quit(exitcode)
# Just ignore this. ## Internal, don't call
# Makes misc.stringify_variables() calls shorter
func stringify_variables(template: String, arguments: Dictionary, no_quotes: bool = false) -> String:
return misc.stringify_variables(template, arguments, no_quotes, true)
## Internal, don't call. ## Internal, don't call.
# 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

@ -54,11 +54,12 @@ func _cleanup() -> void:
## [/codeblock] ## [/codeblock]
## [b]Note: [i]Using the [code]await[/code] keyword is required for this function.[/i][/b] ## [b]Note: [i]Using the [code]await[/code] keyword is required for this function.[/i][/b]
func awaited_request(url: String, parse_utf8: bool, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), data: String = "") -> Dictionary: func awaited_request(url: String, parse_utf8: bool, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), data: String = "") -> Dictionary:
loggeri.verb("Creating awaited request") logger.verb("Creating awaited request")
if !await is_url_allowed(url): return {} if !await is_url_allowed(url): return {}
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)
loggeri.diag("Waiting for request " + str(id) + " to finish") logger.diag("Waiting for request " + str(id) + " to finish")
logger.diag(core.stringify_variables("Waiting for request %id% to finish", { "id": id }))
while !is_request_completed(id): await get_tree().create_timer(0.1, true).timeout while !is_request_completed(id): await get_tree().create_timer(0.1, true).timeout
var dldata: Dictionary = list_complete[id] var dldata: Dictionary = list_complete[id]
list_complete.erase(id) list_complete.erase(id)
@ -93,7 +94,7 @@ func oneline_awaited_request(url: String, return_utf8: bool = true, ignore_http_
## [/codeblock] ## [/codeblock]
## [b]Note: [i]Using the [code]await[/code] keyword is required for this function.[/i][/b] ## [b]Note: [i]Using the [code]await[/code] keyword is required for this function.[/i][/b]
func batch_awaited_request(urls: PackedStringArray, parse_utf8: bool, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), data: String = "") -> Array[Dictionary]: func batch_awaited_request(urls: PackedStringArray, parse_utf8: bool, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), data: String = "") -> Array[Dictionary]:
loggeri.verb("Creating " + str(urls.size()) + " awaited request(s)") logger.verb("Creating " + str(urls.size()) + " awaited request(s)")
var dldata: Array[Dictionary] = [] var dldata: Array[Dictionary] = []
for url in urls: for url in urls:
if !await is_url_allowed(url): continue if !await is_url_allowed(url): continue
@ -108,7 +109,7 @@ func batch_awaited_request(urls: PackedStringArray, parse_utf8: bool, method: HT
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)
loggeri.diag("Waiting for request " + str(id) + " to finish") logger.diag(core.stringify_variables("Waiting for request %id% to finish", { "id": id }))
while !is_request_completed(id): await get_tree().create_timer(0.1, true).timeout while !is_request_completed(id): await get_tree().create_timer(0.1, true).timeout
return id return id
@ -117,15 +118,15 @@ func _batch_awaited_request(url: String, parse_utf8: bool, method: HTTPClient.Me
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):
loggeri.warn("New download id '" + str(id) + "' is already taken") logger.warn(core.stringify_variables("New download id %id% already taken", { "id": id }))
return generate_id() return generate_id()
loggeri.diag("Generated new download id " + str(id)) logger.diag(core.stringify_variables("Generated new download id %id%", { "id": id }))
return id return id
## Creates a new request and stores it in the queue. Returns the download id.[br] ## Creates a new request and stores it in the queue. Returns the download id.[br]
## [b]Warning: [i]You'll probably not need this. Only use this function when implementing your own downloading method.[/i][/b] ## [b]Warning: [i]You'll probably not need this. Only use this function when implementing your own downloading method.[/i][/b]
func create_request(url: String, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), body: String = "") -> int: func create_request(url: String, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), body: String = "") -> int:
loggeri.verb("Creating new request\n-> URL: " + url + "\n-> Method: " + str(method) + "\nHeaders: " + str(headers.size()) + "\nBody size: " + str(body.length()) + " Characters") logger.verb("Creating new request\n-> URL: " + url + "\n-> Method: " + str(method) + "\nHeaders: " + str(headers.size()) + "\nBody size: " + str(body.length()) + " Characters")
var id = generate_id() var id = generate_id()
list_queue.merge({ id: { "url": url, "method": method, "headers": headers, "body": body } }) list_queue.merge({ id: { "url": url, "method": method, "headers": headers, "body": body } })
return id return id
@ -134,16 +135,17 @@ func create_request(url: String, method: HTTPClient.Method = HTTPClient.Method.M
## [b]Note: [i]Using the [code]await[/code] keyword is required for this function.[/i][/b][br] ## [b]Note: [i]Using the [code]await[/code] keyword is required for this function.[/i][/b][br]
## [b]Warning: [i]You'll probably not need this. Only use this function when implementing your own downloading method.[/i][/b] ## [b]Warning: [i]You'll probably not need this. Only use this function when implementing your own downloading method.[/i][/b]
func start_request(id: int, parse_utf8: bool) -> void: func start_request(id: int, parse_utf8: bool) -> void:
loggeri.verb("Starting request " + str(id)) logger.verb("Starting request " + str(id))
logger.verb(core.stringify_variables("Starting request %id%", { "id": id }))
list_active.merge({ id: list_queue[id] }) list_active.merge({ id: list_queue[id] })
list_queue.erase(id) list_queue.erase(id)
loggeri.diag("Creating new HTTPRequest \"Request #" + str(id) + "\"") logger.diag("Creating new HTTPRequest \"Request #" + str(id) + "\"")
var download: HTTPRequest = HTTPRequest.new() var download: HTTPRequest = HTTPRequest.new()
download.name = "Request #" + str(id) download.name = "Request #" + str(id)
download.accept_gzip = true download.accept_gzip = true
download.use_threads = true download.use_threads = true
var lambda: Callable = func(result: int, http_code: int, headers: PackedStringArray, body: PackedByteArray, httprequest: HTTPRequest) -> void: var lambda: Callable = func(result: int, http_code: int, headers: PackedStringArray, body: PackedByteArray, httprequest: HTTPRequest) -> void:
loggeri.verb("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\nParse body as UTF-8: " + str(parse_utf8)) logger.verb(core.stringify_variables("Request %id% completed\nResult: %result%\nHTTP response code: %http_code%\nHeaders: %headers%\nBody size: %body_size_bytes% Bytes // %body_size_mib% MiB\nParsed body as UTF-8: %parse_utf8%", { "result": result, "http_code": http_code, "headers": headers.size(), "body_size_bytes": body.size(), "body_size_mib": core.misc.byte2mib(body.size(), true), "parse_utf8": parse_utf8 }, true))
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_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) list_active.erase(id)
remove_child(httprequest) remove_child(httprequest)
@ -157,14 +159,14 @@ func is_url_allowed(url: String) -> bool:
if url.begins_with("http://"): if url.begins_with("http://"):
match(config_unsecure_requests): match(config_unsecure_requests):
CoreTypes.BlockadeLevel.BLOCK: CoreTypes.BlockadeLevel.BLOCK:
loggeri.error("Blocked unsecure url '" + url + "'") logger.error(core.stringify_variables("Blocked unsecure url %url%", { "url": url }))
return false return false
CoreTypes.BlockadeLevel.WARN: loggeri.warn("Requesting unsecure url '" + url + "'") CoreTypes.BlockadeLevel.WARN: logger.warn(core.stringify_variables("Requesting unsecure url %url%", { "url": url }))
CoreTypes.BlockadeLevel.IGNORE: pass CoreTypes.BlockadeLevel.IGNORE: pass
_: await loggeri.crash("Invalid BlockadeLevel '" + str(config_unsecure_requests) + "'") _: await logger.crash(core.stringify_variables("Invalid BlockadeLevel %level%", { "level": config_unsecure_requests }))
elif url.begins_with("https://"): pass elif url.begins_with("https://"): pass
else: else:
loggeri.error("Invalid url '" + url + "'") logger.error(core.stringify_variables("Invalid url %url%", { "url": url }))
return false return false
return true return true
@ -173,10 +175,10 @@ func is_request_completed(id: int) -> bool: return list_complete.has(id)
## Cleans the request queue. ## Cleans the request queue.
func clean_queue() -> void: func clean_queue() -> void:
loggeri.verb("Cleaning request queue") logger.verb("Cleaning request queue")
list_queue.clear() list_queue.clear()
## Cleans the completed requests list. ## Cleans the completed requests list.
func clean_completed() -> void: func clean_completed() -> void:
loggeri.verb("Cleaning completed requests") logger.verb("Cleaning completed requests")
list_complete.clear() list_complete.clear()

View file

@ -46,7 +46,7 @@ var config_newlines_sizelimit: int
func _cleanup() -> void: func _cleanup() -> void:
for instance in instances: for instance in instances:
if is_instance_valid(instance): if is_instance_valid(instance):
loggeri.diag("Removing instance '" + instance.name + "'") logger.diag("Removing instance '" + instance.name + "'")
instance.queue_free() instance.queue_free()
func _schedule() -> void: func _schedule() -> void:
@ -54,7 +54,7 @@ func _schedule() -> void:
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 + "'") logger.diag("Removing instance '" + instance.name + "'")
instance.queue_free() instance.queue_free()
instances_remove_enty.append(instance) instances_remove_enty.append(instance)
for instance in instances_remove_enty: for instance in instances_remove_enty:

View file

@ -90,7 +90,7 @@ func _ready() -> void:
vsbar.add_theme_stylebox_override("grabber_pressed", StyleBoxEmpty.new()) vsbar.add_theme_stylebox_override("grabber_pressed", StyleBoxEmpty.new())
# Connect log_event # 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") core.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")
# +++ process +++ # +++ process +++
func _process(_delta: float) -> void: func _process(_delta: float) -> void:

View file

@ -85,10 +85,10 @@ func format_stringarray(array: Array[String], item_before: String = "", item_aft
var output: String = "" var output: String = ""
if array.size() == 0: if array.size() == 0:
loggeri.warn("Unable to format a string with a size of 0") logger.warn("Unable to format a string with a size of 0")
return "" return ""
elif array.size() == 1: elif array.size() == 1:
loggeri.warn("Unable to format a string with a size of 1") logger.warn("Unable to format a string with a size of 1")
return array[0] return array[0]
for item in array: for item in array:
@ -107,7 +107,7 @@ func array_to_stringarray(array: Array) -> Array[String]:
for item in array: for item in array:
if typeof(item) != TYPE_STRING: if typeof(item) != TYPE_STRING:
logger.error("Cannot convert Array to Array[String]: Item '" + str(item) + "' is not of type String") logger.error(core.stringify_string("Cannot convert Array to Array[String]: Item %item% is not of type String", { "item": item }))
return [] return []
output.append(item) output.append(item)
@ -151,7 +151,7 @@ func get_center(parent_size: Vector2, child_size: Vector2) -> Vector2:
## Output: ## Output:
## [16:44:35] [DIAG Test.gd] Triggered '"shoot"' (pos='x=5156.149 y=581.69', successful='true') ## [16:44:35] [DIAG Test.gd] Triggered '"shoot"' (pos='x=5156.149 y=581.69', successful='true')
## [/codeblock] ## [/codeblock]
func stringify_variables(template: String, variables: Dictionary, no_quotes: bool = false) -> String: func stringify_variables(template: String, variables: Dictionary, no_quotes: bool = false, force_no_type: bool = false) -> String:
# To decrease allocations # To decrease allocations
var value var value
var type: String = "" var type: String = ""
@ -286,7 +286,7 @@ func stringify_variables(template: String, variables: Dictionary, no_quotes: boo
type = "unknown" type = "unknown"
# Replace # Replace
if config_stringify_show_type: if config_stringify_show_type and !force_no_type:
if type != "": type = "(" + type.to_lower() + ") " if type != "": type = "(" + type.to_lower() + ") "
else: else:
type = "" type = ""
@ -294,7 +294,7 @@ func stringify_variables(template: String, variables: Dictionary, no_quotes: boo
template = template.replace("%" + placeholder + "%", quote + type + replacement + quote) template = template.replace("%" + placeholder + "%", quote + type + replacement + quote)
return template return template
# Makes calls shorter # Makes internal calls shorter
func _sa(value) -> String: func _sa(value) -> String:
return stringify_variables("%var%", { "var": value }, true) return stringify_variables("%var%", { "var": value }, true)

View file

@ -49,19 +49,19 @@ func _cleanup() -> void:
func _pull_config() -> void: func _pull_config() -> void:
if core.config.headless: if core.config.headless:
# Remove all scenes # Remove all scenes
if is_inside_tree(): loggeri.verb("Removing all scenes (triggered by headless mode)") if is_inside_tree(): logger.verb("Removing all scenes (triggered by headless mode)")
for scene in scenes: remove_scene(scene, true) for scene in scenes: remove_scene(scene, true)
# +++ scene management +++ # +++ scene management +++
## Adds a scene to some scene collection. ## Adds a scene to some scene collection.
func add_scene(scene_name: String, scene_class: Node, scene_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 \"" + scene_name + "\" of type " + str(scene_type)) logger.verb(core.stringify_variables("Adding scene %name% of type %type%", { "name": scene_name, "type": scene_type }))
if exists(scene_name) != CoreTypes.SceneType.NONE: if exists(scene_name) != CoreTypes.SceneType.NONE:
loggeri.error("Scene with name \"" + scene_name + "\" already exists") logger.error(core.stringify_variables("A scene named %name% already exists", { "name": scene_name }))
return false return false
if typeof(scene_class) != TYPE_OBJECT or !scene_class.is_class("Node"): if typeof(scene_class) != TYPE_OBJECT or !scene_class.is_class("Node"):
loggeri.error("Scene class \"" + scene_name + "\" is not of type Node") logger.error(core.stringify_variables("Scene class %name% is not of type Node", { "name": scene_name }))
return false return false
scene_class.name = scene_name scene_class.name = scene_name
match(scene_type): match(scene_type):
@ -71,9 +71,9 @@ func add_scene(scene_name: String, scene_class: Node, scene_type: CoreTypes.Scen
CoreTypes.SceneType.MAIN: scenes_main.add_child(scene_class) CoreTypes.SceneType.MAIN: scenes_main.add_child(scene_class)
CoreTypes.SceneType.BACKGROUND: scenes_background.add_child(scene_class) 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") logger.error("CoreTypes.SceneType.NONE is not a valid scene type")
return false return false
_: await loggeri.crash("Invalid SceneType " + str(scene_type)) _: await logger.crash(core.stringify_variables("Invalid SceneType %type%", { "type": scene_type }))
scenes.merge({ scene_name: { "type": scene_type, "class": scene_class } }) scenes.merge({ scene_name: { "type": scene_type, "class": scene_class } })
return true return true
@ -81,8 +81,8 @@ func add_scene(scene_name: String, scene_class: Node, scene_type: CoreTypes.Scen
## [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(scene_name: 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 logger.crash("force_remove is not allowed to be true")
loggeri.verb("Removing scene \"" + scene_name + "\"") logger.verb(core.stringify_variables("Removing scene %name%", { "name": scene_name }))
match(exists(scene_name)): match(exists(scene_name)):
CoreTypes.SceneType.DEBUG: CoreTypes.SceneType.DEBUG:
scenes_debug.remove_child(scenes[scene_name]["class"]) scenes_debug.remove_child(scenes[scene_name]["class"])
@ -100,9 +100,9 @@ func remove_scene(scene_name: String, force_remove: bool = false) -> bool:
scenes_background.remove_child(scenes[scene_name]["class"]) scenes_background.remove_child(scenes[scene_name]["class"])
scenes[scene_name]["class"].queue_free() scenes[scene_name]["class"].queue_free()
CoreTypes.SceneType.NONE: CoreTypes.SceneType.NONE:
loggeri.error("Scene \"" + scene_name + "\" does not exist") logger.error(core.stringify_variables("Scene %name% does not exist", { "name": scene_name }))
return false return false
_: await loggeri.crash("Invalid SceneType " + str(exists(scene_name))) _: await logger.crash(core.stringify_variables("Invalid SceneType %type%", { "type": exists(scene_name) }))
scenes.erase(scene_name) scenes.erase(scene_name)
return true return true
@ -118,8 +118,8 @@ func get_scene(scene_name: String) -> Node:
CoreTypes.SceneType.MENU: return scenes[scene_name]["class"] CoreTypes.SceneType.MENU: return scenes[scene_name]["class"]
CoreTypes.SceneType.MAIN: return scenes[scene_name]["class"] CoreTypes.SceneType.MAIN: return scenes[scene_name]["class"]
CoreTypes.SceneType.BACKGROUND: return scenes[scene_name]["class"] CoreTypes.SceneType.BACKGROUND: return scenes[scene_name]["class"]
CoreTypes.SceneType.NONE: loggeri.error("Scene \"" + scene_name + "\" does not exist") CoreTypes.SceneType.NONE: logger.error(core.stringify_variables("Scene %name% does not exist", { "name": scene_name }))
_: await loggeri.crash("Invalid SceneType " + str(exists(scene_name))) _: await logger.crash(core.stringify_variables("Invalid SceneType %type%", { "type": exists(scene_name) }))
return null return null
## Returns a scene collection node.[br] ## Returns a scene collection node.[br]
@ -133,8 +133,8 @@ func get_scene_collection(scene_type: CoreTypes.SceneType) -> Node:
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: logger.error("No scene collection was found for CoreTypes.SceneType.NONE")
_: await loggeri.crash("Invalid SceneType " + str(scene_type)) _: await logger.crash(core.stringify_variables("Invalid SceneType %type%", { "type": 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.

View file

@ -32,40 +32,40 @@ var storage_location: String = ""
## Opens a storage file and loads it 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") logger.error("Failed to open storage: A storage file is already open")
return false return false
loggeri.verb("Opening storage file at \"" + location + "\"") logger.verb(core.stringify_variables("Opening storage file at %location%", { "location": location }))
var file: FileAccess var file: FileAccess
if !FileAccess.file_exists(location): if !FileAccess.file_exists(location):
if create_new: if create_new:
file = FileAccess.open(location, FileAccess.WRITE) file = FileAccess.open(location, FileAccess.WRITE)
if file == null: if file == null:
await loggeri.crash("Could not open storage file at \"" + location + "\": Failed with code " + str(FileAccess.get_open_error())) await logger.crash(core.stringify_variables("Could not open storage file at %location%: Failed with error %error%", { "location": location, "error": error_string(FileAccess.get_open_error()) }))
return false return false
file.store_string("{}") file.store_string("{}")
file.close() file.close()
else: else:
loggeri.error("Failed to open storage: create_new is set to false") logger.error("Failed to open storage: create_new is set to false")
return false return false
file = FileAccess.open(location, FileAccess.READ) file = FileAccess.open(location, FileAccess.READ)
var storage_temp: Variant = file.get_as_text() var storage_temp: Variant = file.get_as_text()
file.close() file.close()
storage_temp = JSON.parse_string(storage_temp) storage_temp = JSON.parse_string(storage_temp)
if typeof(storage_temp) != TYPE_DICTIONARY: if typeof(storage_temp) != TYPE_DICTIONARY:
loggeri.error("Failed to open storage: Parsed storage file is of type " + str(typeof(storage_temp))) logger.error(core.stringify_variables("Failed to open storage: Parsed storage file is of type %type%", { "type": type_string(typeof(storage_temp)) }))
return false return false
if sanity_check: if sanity_check:
var check_result: Array[String] = perform_sanity_check(storage_temp) var check_result: Array[String] = perform_sanity_check(storage_temp)
if check_result.size() != 0: if check_result.size() != 0:
if fail_on_sanity_check: if fail_on_sanity_check:
loggeri.error("Sanity check failed (stopping):") logger.error("Sanity check failed (stopping):")
for error in check_result: for error in check_result:
loggeri.error("-> " + error) logger.error("-> " + error)
return false return false
else: else:
loggeri.warn("Sanity check failed (continuing anyway):") logger.warn("Sanity check failed (continuing anyway):")
for error in check_result: for error in check_result:
loggeri.warn("-> " + error) logger.warn("-> " + error)
storage = storage_temp storage = storage_temp
storage_location = location storage_location = location
is_open = true is_open = true
@ -74,9 +74,9 @@ func open_storage(location: String, create_new: bool = true, sanity_check: bool
## Closes the active storage file. ## Closes the active storage file.
func close_storage() -> bool: func close_storage() -> bool:
if !is_open: if !is_open:
loggeri.error("Failed to close storage: No storage file is open") logger.error("Failed to close storage: No storage file is open")
return false return false
loggeri.verb("Closing storage file") logger.verb("Closing storage file")
storage = {} storage = {}
is_open = false is_open = false
return true return true
@ -84,13 +84,13 @@ func close_storage() -> bool:
## Saves the active storage file to disk. ## Saves the active storage file to disk.
func save_storage() -> bool: func save_storage() -> bool:
if !is_open: if !is_open:
loggeri.error("Failed to save storage: No storage file is open") logger.error("Failed to save storage: No storage file is open")
return false return false
var file: FileAccess = FileAccess.open(storage_location, FileAccess.WRITE) var file: FileAccess = FileAccess.open(storage_location, FileAccess.WRITE)
if file == null: if file == null:
await loggeri.crash("Could not open storage file at \"" + storage_location + "\": Failed with code " + str(FileAccess.get_open_error())) await logger.crash(core.stringify_variables("Could not open storage file at %location%: Failed with error %error%", { "location": storage_location, "error": error_string(FileAccess.get_open_error()) }))
return false return false
loggeri.diag("Writing storage file to disk") logger.diag("Writing storage file to disk")
file.store_string(JSON.stringify(storage)) file.store_string(JSON.stringify(storage))
file.close() file.close()
return true return true
@ -99,9 +99,9 @@ func save_storage() -> bool:
## Removes all keys from the active storage file. The nuclear option basically. ## Removes all keys from the active storage file. The nuclear option basically.
func nuke_storage(autosave: bool = true) -> bool: func nuke_storage(autosave: bool = true) -> bool:
if !is_open: if !is_open:
loggeri.error("Failed to nuke storage: No storage file is open") logger.error("Failed to nuke storage: No storage file is open")
return false return false
loggeri.warn("Nuking storage") logger.warn("Nuking storage")
storage = {} storage = {}
if autosave: save_storage() if autosave: save_storage()
return true return true
@ -109,17 +109,17 @@ func nuke_storage(autosave: bool = true) -> bool:
## Returns a storage key. Can also return a default value if unset. ## Returns a storage key. Can also return a default value if unset.
func get_key(key: String, default: Variant = null) -> Variant: func get_key(key: String, default: Variant = null) -> Variant:
if !is_open: if !is_open:
loggeri.error("Failed to get key: No storage file is open") logger.error("Failed to get key: No storage file is open")
return NAN return NAN
loggeri.diag("Returning storage key \"" + key + "\" (default='" + str(default) + "')") logger.diag(core.stringify_variables("Returning storage key %key% (default=%default%)", { "key": key, "default": default }))
return storage.get(key, default) return storage.get(key, default)
## Updates a storage key with the specified value. ## Updates a storage key with the specified value.
func set_key(key: String, value: Variant, overwrite: bool = true, autosave: bool = true) -> bool: func set_key(key: String, value: Variant, overwrite: bool = true, autosave: bool = true) -> bool:
if !is_open: if !is_open:
loggeri.error("Failed to set key: No storage file is open") logger.error("Failed to set key: No storage file is open")
return false return false
loggeri.diag("Updating storage key \"" + key + "\" with value '" + str(value) + "' (overwrite='" + str(overwrite) + "' autosave='" + str(autosave) + "'") logger.diag(core.stringify_variables("Updating storage key %key% with value %value% (overwrite=%overwrite% autosave=%autosave%)", { "key": key, "value": value, "overwrite": overwrite, "autosave": autosave }))
storage.merge({key: value}, overwrite) storage.merge({key: value}, overwrite)
if autosave: save_storage() if autosave: save_storage()
return true return true
@ -129,7 +129,7 @@ func del_key(key: String, autosave: bool = true) -> bool:
if !is_open: if !is_open:
logger.errof("storage", "Failed to delete key: No storage file is open") logger.errof("storage", "Failed to delete key: No storage file is open")
return false return false
loggeri.diag("Deleting storage key \"" + key + "\" (autosave='" + str(autosave) + "')") logger.diag(core.stringify_variables("Deleting storage key %key% (autosave=%autosave%)", { "key": key, "autosave": autosave }))
storage.erase(key) storage.erase(key)
if autosave: save_storage() if autosave: save_storage()
return true return true
@ -139,30 +139,30 @@ func del_key(key: String, autosave: bool = true) -> bool:
## pass your modified [class Dictionary to [method safe_dict]. ## pass your modified [class Dictionary to [method safe_dict].
func get_dict() -> Dictionary: func get_dict() -> Dictionary:
if !is_open: if !is_open:
loggeri.error("Failed to get dictionary: No storage file is open") logger.error("Failed to get dictionary: No storage file is open")
return {} return {}
loggeri.verb("Returning storage dictionary") logger.verb("Returning storage dictionary")
return storage return storage
# +++ raw manipulation +++ # +++ raw manipulation +++
## Saves a arbitrary dictionary as a [param storage] [class Dictionary] with sanity checking ([code]sanity_check[/code] and [code]fail_on_sanity_check[/code]). ## Saves a arbitrary dictionary as a [param storage] [class Dictionary] with sanity checking ([code]sanity_check[/code] and [code]fail_on_sanity_check[/code]).
func save_dict(dict: Dictionary, sanity_check: bool = true, fail_on_sanity_check: bool = false, autosave: bool = true) -> bool: func save_dict(dict: Dictionary, sanity_check: bool = true, fail_on_sanity_check: bool = false, autosave: bool = true) -> bool:
if !is_open: if !is_open:
loggeri.error("Failed to save dictionary: No storage file is open") logger.error("Failed to save dictionary: No storage file is open")
return false return false
loggeri.verb("Saving custom dictionary as storage") logger.verb("Saving custom dictionary as storage")
if sanity_check: if sanity_check:
var check_result: Array[String] = perform_sanity_check(dict) var check_result: Array[String] = perform_sanity_check(dict)
if check_result.size() != 0: if check_result.size() != 0:
if fail_on_sanity_check: if fail_on_sanity_check:
loggeri.error("Sanity check failed (stopping):") logger.error("Sanity check failed (stopping):")
for error in check_result: for error in check_result:
loggeri.error("-> " + error) logger.error("-> " + error)
return false return false
else: else:
loggeri.warn("Sanity check failed (continuing anyway):") logger.warn("Sanity check failed (continuing anyway):")
for error in check_result: for error in check_result:
loggeri.warn("-> " + error) logger.warn("-> " + error)
storage = dict storage = dict
if autosave: save_storage() if autosave: save_storage()
return true return true
@ -170,14 +170,14 @@ func save_dict(dict: Dictionary, sanity_check: bool = true, fail_on_sanity_check
# +++ etc +++ # +++ etc +++
## Performs sanity checks on a [class Dictionary] to determine if it can be saved and loaded using this module. ## Performs sanity checks on a [class Dictionary] to determine if it can be saved and loaded using this module.
func perform_sanity_check(storage_check: Dictionary) -> Array[String]: func perform_sanity_check(storage_check: Dictionary) -> Array[String]:
loggeri.verb("Performing a sanity check on some storage dictionary") logger.verb("Performing a sanity check on some storage dictionary")
var errors: Array[String] = [] var errors: Array[String] = []
for key in storage_check: for key in storage_check:
if typeof(key) != TYPE_STRING: if typeof(key) != TYPE_STRING:
errors.append("Key \"" + str(key) + "\" is not of type String (type '" + type_string(typeof(key)) + "')") errors.append(core.stringify_variables("Key %key% is not of type String (is of type %type%)", { "key": key, "type": type_string(typeof(key)) }))
continue continue
if typeof(storage_check[key]) != TYPE_NIL and typeof(storage_check[key]) != TYPE_STRING and typeof(storage_check[key]) != TYPE_INT and typeof(storage_check[key]) != TYPE_FLOAT and typeof(storage_check[key]) != TYPE_BOOL and typeof(storage_check[key]) != TYPE_ARRAY and typeof(storage_check[key]) != TYPE_DICTIONARY: if typeof(storage_check[key]) != TYPE_NIL and typeof(storage_check[key]) != TYPE_STRING and typeof(storage_check[key]) != TYPE_INT and typeof(storage_check[key]) != TYPE_FLOAT and typeof(storage_check[key]) != TYPE_BOOL and typeof(storage_check[key]) != TYPE_ARRAY and typeof(storage_check[key]) != TYPE_DICTIONARY:
errors.append("The value of \"" + key + "\" is not null, a string, an integer, a float, boolean, array or dictionary (type '" + type_string(typeof(key)) + "')") errors.append(core.stringify_variables("The value of %key% is not null, a String, an int, a float, boolean, an Array or a Dictionary (is of type %type%)", { "key": key, "type": type_string(typeof(key)) }))
loggeri.verb("Completed sanity check with " + str(errors.size()) + " errors") logger.verb(core.stringify_variables("Completed sanity check with %errors% errors", { "errors": errors.size() }))
return errors return errors