This commit is contained in:
JeremyStar™ 2024-04-10 00:59:36 +02:00
parent ed0670eac9
commit 2465e8ef71
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
5 changed files with 85 additions and 40 deletions

View file

@ -38,6 +38,9 @@ func _initialize() -> void: initialized = true
## Use this function to remove any children from the SceneTree and free any nodes.[br]
## If not done you might cause a memory leak.
func _cleanup() -> void: pass
## Called periodically by CORE's scheduler.[br]
## Use this function to clean up any temporary things.
func _schedule() -> void: pass
## Called after CORE's configuration got updated.[br]
## Probably useless to your module, unless you want to modify another module's settings.
func _pull_config() -> void: pass

View file

@ -12,10 +12,9 @@ class_name CoreConfiguration
## Controls CORE's functionality.[br]
## Renders GUI-related modules useless when set to [code]false[/code], which is the recommended behaviour on servers. For CORE's full functionality, set this to [code]true[/code].
@export var headless: bool
## Allows debugging functionality if set to [code]true[/code], or not if set to [code]false[/code].[br]
## [br]
## [b]Note: [i]This will not enable the development mode automatically, only if you're developing on CORE itself.[/i][/b]
@export var debugging: bool
## Puts the framework into development mode.[br]
## Unlocks experimental features.
@export var development: bool
## Allows or disallows custom modules.
@export var custom_modules: bool
@export_category("Logger")
@ -45,7 +44,7 @@ class_name CoreConfiguration
func _init() -> void:
# Global
headless = false
debugging = false
development = false
custom_modules = false
# Logger

View file

@ -28,14 +28,18 @@ class_name CoreLoggerInstance
var logger: CoreBaseModule
## The origin argument.
var origin: String
## For internal purposes only.
## Indicates that the parent class is part of the CORE Framework.
## [b]Note: [i]Don't modify.[/i][/b]
var framework: bool = false
## Is set to the parent owning the logger instance.
## [b]Note: [i]Don't modify.[/i][/b]
var parent: Object
## The instance constructor.
func _init(logger_new: CoreBaseModule, origin_new: String) -> void:
func _init(logger_new: CoreBaseModule, origin_new: String, parent_new: Object) -> void:
logger = logger_new
origin = origin_new
parent = parent_new
## Prints a diagnostic message.
func diag(message: String) -> void: logger.diag(origin, message)

View file

@ -36,6 +36,10 @@ const modules: Array[String] = [ "logger", "misc", "sms", "logui", "erm", "stora
## CORE's configuration object.[br]
## [b]NEVER access this yourself! To change the configuration use [method reload_configuration] instead.[/b]
var config: CoreConfiguration
## The framework scheduler.[br]
## Performs various maintenance tasks every minute.
## [b]Danger: [i]Don't modify this.[/i][/b]
var scheduler: Timer
## The 'Logger' module
var logger: CoreBaseModule
## The 'Miscellaneous' module
@ -73,6 +77,7 @@ func _init(new_config: CoreConfiguration = CoreConfiguration.new()) -> void:
reload_configuration(new_config)
initialize_modules()
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]
@ -80,7 +85,8 @@ func _ready() -> void:
inject_modules()
custom_modules_node.name = "Custom Modules"
add_child(custom_modules_node)
loggeri = logger.get_instance(basepath.replace("res://", "") + "src/core.gd")
loggeri = logger.get_instance(basepath.replace("res://", "") + "src/core.gd", self)
add_child(scheduler)
## Initializes all built-in modules during the preinitialization phase.[br]
## [b]Danger: [i]Don't call this.[/i][/b]
@ -90,13 +96,29 @@ func initialize_modules() -> void:
get(module).name = module
get(module).set_script(load(basepath + "src/" + module + ".gd"))
get(module).core = self
get(module).loggeri = logger.get_instance(basepath.replace("res://", "") + "src/" + module + ".gd")
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]
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]
func initialize_scheduler() -> void:
scheduler = Timer.new()
scheduler.name = "Scheduler"
scheduler.autostart = true
scheduler.one_shot = false
scheduler.paused = false
scheduler.wait_time = 60
scheduler.process_mode = Node.PROCESS_MODE_ALWAYS
scheduler.connect("timeout", func() -> void:
loggeri.verb("Running scheduler tasks")
for module in modules: await get(module)._schedule()
for module in custom_modules_node.get_children(): await module._schedule()
)
## Waits for all modules to fully initialize.[br]
## [br]
## This ensures that all modules are fully initialized and ready for usage.[br]
@ -128,6 +150,33 @@ func complete_init(no_success_message: bool = false) -> void:
await get_tree().process_frame
if !no_success_message: loggeri.info("Initialized CORE successfully")
# +++ configuration +++
## Loads a (new) configuration object and applies it to all modules.
func reload_configuration(new_config: CoreConfiguration = CoreConfiguration.new()) -> void:
var initialized = config != null
if initialized: loggeri.verb("Reloading CORE's configuration")
if config != null: config.queue_free()
config = new_config
if is_devmode(): # Override configuration in development mode
config.logger_level = CoreTypes.LoggerLevel.DIAG
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]
func apply_configuration() -> void:
if loggeri != null: loggeri.verb("Applying configuration")
if is_devmode(): if loggeri != null: loggeri.warn("The CORE Framework is in development mode. Here be dragons!")
if config.headless: loggeri.warn("CORE is in headless mode. Certain modules will not work as expected.")
if !config.custom_modules:
if loggeri != null: loggeri.verb("Removing all custom modules (custom modules support is disabled)")
for module in custom_modules: unregister_custom_module(module)
for module in modules: get(module)._pull_config()
if config.custom_modules:
for module in custom_modules:
if loggeri != null: loggeri.diag("Updating configuration for custom module \"" + module.name + "\"")
module._pull_config()
# +++ custom module support +++
## Registers a new custom module.
func register_custom_module(module_name: String, module_origin: String, module_class: CoreBaseModule) -> bool:
@ -141,7 +190,7 @@ func register_custom_module(module_name: String, module_origin: String, module_c
loggeri.diag("Updating variables")
module_class.name = module_name
module_class.core = self
module_class.loggeri = logger.get_instance(module_origin)
module_class.loggeri = logger.get_instance(module_origin, module_class)
module_class.loggeri.framework = true
loggeri.diag("Adding module to SceneTree")
custom_modules_node.add_child(module_class)
@ -175,33 +224,6 @@ func get_custom_module(module_name: String) -> CoreBaseModule:
return null
return custom_modules[module_name]
# +++ configuration +++
## Loads a (new) configuration object and applies it to all modules.
func reload_configuration(new_config: CoreConfiguration = CoreConfiguration.new()) -> void:
var initialized = config != null
if initialized: loggeri.verb("Reloading CORE's configuration")
if config != null: config.queue_free()
config = new_config
if is_devmode(): # Override configuration in development mode
config.logger_level = CoreTypes.LoggerLevel.VERB
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]
func apply_configuration() -> void:
if loggeri != null: loggeri.verb("Applying configuration")
if is_devmode(): if loggeri != null: loggeri.warn("The CORE Framework is in development mode. Here be dragons!")
if config.headless: loggeri.warn("CORE is in headless mode. Certain modules will not work as expected.")
if !config.custom_modules:
if loggeri != null: loggeri.verb("Removing all custom modules (custom modules support is disabled)")
for module in custom_modules: unregister_custom_module(module)
for module in modules: get(module)._pull_config()
if config.custom_modules:
for module in custom_modules:
if loggeri != null: loggeri.diag("Updating configuration for custom module \"" + module.name + "\"")
module._pull_config()
# +++ etc ++
## 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.
@ -219,9 +241,9 @@ func cleanup() -> void:
custom_modules_node.queue_free()
queue_free()
## Returns if the CORE Framework is in development mode.
## Returns if the framework is in development mode.
func is_devmode() -> bool:
return config.debugging and basepath == "res://" and OS.is_debug_build()
return config.development
## Replaces placeholders with human-friendly strings.[br]
## You can use the following placeholders:[br]

View file

@ -23,6 +23,11 @@ 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]
var instances: Array[CoreLoggerInstance] = []
## The minimum log level you want to be displayed.
var config_level: CoreTypes.LoggerLevel
## Determines if the logger's output should be colored.
@ -36,6 +41,14 @@ var config_newlines_override: bool
var config_newlines_sizelimit: int
# +++ module +++
func _schedule() -> void:
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))
func _pull_config() -> void:
config_level = core.config.logger_level
config_colored = core.config.logger_colored
@ -203,4 +216,8 @@ func is_level_allowed(level: CoreTypes.LoggerLevel) -> bool:
else: return false
## Returns a [class CoreLoggerInstance], which is a fancy word meaning you don't need to pass [code]origin[/code] every time you want to log something.
func get_instance(origin: String) -> CoreLoggerInstance: return CoreLoggerInstance.new(self, origin)
func get_instance(origin: String, parent: Object) -> CoreLoggerInstance:
var instance: CoreLoggerInstance = CoreLoggerInstance.new(self, origin, parent)
instance.name = "CoreLoggerInstance -> " + str(parent) + " (" + origin + ")"
instances.append(instance)
return instance