Introduce scheduler and add CoreLoggerInstance cleanup (#17)
This commit is contained in:
parent
bf7eacdb39
commit
d2735361b0
9 changed files with 105 additions and 38 deletions
3
Test.gd
3
Test.gd
|
@ -24,13 +24,12 @@ extends Node
|
||||||
|
|
||||||
var core: Core
|
var core: Core
|
||||||
var config: CoreConfiguration = CoreConfiguration.new()
|
var config: CoreConfiguration = CoreConfiguration.new()
|
||||||
@onready var logger: CoreLoggerInstance = core.logger.get_instance("Test.gd")
|
@onready var logger: CoreLoggerInstance = core.logger.get_instance("Test.gd", self)
|
||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
# Update config keys
|
# Update config keys
|
||||||
config.headless = false
|
config.headless = false
|
||||||
config.development = true
|
config.development = true
|
||||||
config.logger_level = CoreTypes.LoggerLevel.DIAG
|
|
||||||
# Initialize CORE with custom config
|
# Initialize CORE with custom config
|
||||||
core = Core.new(config)
|
core = Core.new(config)
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ CORE's version type number. Resets on every new version and version type.
|
||||||
## Modules
|
## Modules
|
||||||
Use these to access CORE's modules.
|
Use these to access CORE's modules.
|
||||||
- [`config`](/reference/coreconfiguration) (**NEVER access this yourself. To change the configuration, use `reload_configuration()` instead**)
|
- [`config`](/reference/coreconfiguration) (**NEVER access this yourself. To change the configuration, use `reload_configuration()` instead**)
|
||||||
|
- `scheduler` (runs clean up tasks periodically)
|
||||||
- [`logger`](/reference/logger)
|
- [`logger`](/reference/logger)
|
||||||
- [`misc`](/reference/misc)
|
- [`misc`](/reference/misc)
|
||||||
- `logui` (not important for developers, displays the log graphically)
|
- `logui` (not important for developers, displays the log graphically)
|
||||||
|
@ -65,6 +66,11 @@ Initializes all built-in modules during the preinitialization phase.
|
||||||
Do not call this.
|
Do not call this.
|
||||||
:::
|
:::
|
||||||
Injects CORE's built-in modules into the SceneTree.
|
Injects CORE's built-in modules into the SceneTree.
|
||||||
|
### *void* <u>initialize_scheduler</u>()
|
||||||
|
:::danger[Don't call]
|
||||||
|
Do not call this.
|
||||||
|
:::
|
||||||
|
Initializes the framework scheduler.
|
||||||
### *void* <u>complete_init</u>(*bool* <u>no_success_message</u> = *false*)
|
### *void* <u>complete_init</u>(*bool* <u>no_success_message</u> = *false*)
|
||||||
Waits for all built-in and custom modules to fully initialize. \
|
Waits for all built-in and custom modules to fully initialize. \
|
||||||
\
|
\
|
||||||
|
|
|
@ -26,6 +26,9 @@ It's **strongly** recommended to initialize your module here or stuff might brea
|
||||||
Called when CORE is about to cleanup. \
|
Called when CORE is about to cleanup. \
|
||||||
Use this function to remove any children from the SceneTree and free any nodes. \
|
Use this function to remove any children from the SceneTree and free any nodes. \
|
||||||
If not done you might cause a memory leak.
|
If not done you might cause a memory leak.
|
||||||
|
### *void* <u>_schedule</u>()
|
||||||
|
Called periodically by CORE's scheduler. \
|
||||||
|
Use this function to clean up any temporary things.
|
||||||
### *void* <u>_pull_config</u>()
|
### *void* <u>_pull_config</u>()
|
||||||
Called after CORE's configuration got updated. \
|
Called after CORE's configuration got updated. \
|
||||||
Probably useless to your module, unless you want to modify another module's settings.
|
Probably useless to your module, unless you want to modify another module's settings.
|
||||||
|
|
|
@ -15,6 +15,14 @@ Emitted on any log call, permitted or not. \
|
||||||
**origin** contains the keys `source`, `source_clean`, `function` and `line`. \
|
**origin** contains the keys `source`, `source_clean`, `function` and `line`. \
|
||||||
**format** is set to `""` when **allowed** is set `false`.
|
**format** is set to `""` when **allowed** is set `false`.
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
### *Array[CoreLoggerInstance]* <u>instances</u> = *[]*
|
||||||
|
:::danger[Don't call]
|
||||||
|
Do not call this.
|
||||||
|
:::
|
||||||
|
Keeps track of all logger instances.
|
||||||
|
Unused instances will be cleaned periodically.
|
||||||
|
|
||||||
## Functions
|
## Functions
|
||||||
### *void* <u>_log</u>(*CoreTypes.LoggerLevel* <u>level</u>, *String* <u>origin</u>, *String* <u>message</u>)
|
### *void* <u>_log</u>(*CoreTypes.LoggerLevel* <u>level</u>, *String* <u>origin</u>, *String* <u>message</u>)
|
||||||
:::danger[Don't call]
|
:::danger[Don't call]
|
||||||
|
@ -41,5 +49,5 @@ Don't set `framework_crash` to `true`, thanks!
|
||||||
Handles crashes. Will terminate your game/application immediately.
|
Handles crashes. Will terminate your game/application immediately.
|
||||||
### *bool* <u>is_level_allowed</u>(*CoreTypes.LoggerLevel* <u>level</u>)
|
### *bool* <u>is_level_allowed</u>(*CoreTypes.LoggerLevel* <u>level</u>)
|
||||||
Checks if the specified log level is allowed by the current configuration.
|
Checks if the specified log level is allowed by the current configuration.
|
||||||
### *CoreLoggerInstance* <u>get_instance</u>(*String* <u>origin</u>)
|
### *CoreLoggerInstance* <u>get_instance</u>(*String* <u>origin</u>, *Object* <u>parent</u>)
|
||||||
Returns a [CoreLoggerInstance](/reference/loggerinstance), which is a fancy word meaning you don't need to pass `origin` every time you want to log something.
|
Returns a [CoreLoggerInstance](/reference/loggerinstance), which is a fancy word meaning you don't need to pass `origin` every time you want to log something.
|
||||||
|
|
|
@ -16,10 +16,15 @@ The origin argument.
|
||||||
:::danger[Don't modify]
|
:::danger[Don't modify]
|
||||||
Do not modify this.
|
Do not modify this.
|
||||||
:::
|
:::
|
||||||
For internal purposes only.
|
Indicates that the parent class is part of the CORE Framework.
|
||||||
|
### *Object* <u>parent</u>
|
||||||
|
:::danger[Don't modify]
|
||||||
|
Do not modify this.
|
||||||
|
:::
|
||||||
|
Is set to the parent owning the logger instance.
|
||||||
|
|
||||||
## Functions
|
## Functions
|
||||||
### *void* <u>_init</u>(*CoreBaseModule* <u>logger_new</u>, *String* <u>origin_new</u>)
|
### *void* <u>_init</u>(*CoreBaseModule* <u>logger_new</u>, *String* <u>origin_new</u>, *Object* <u>parent</u>)
|
||||||
The instance constructor.
|
The instance constructor.
|
||||||
### *void* <u>diag</u>(*String* <u>message</u>)
|
### *void* <u>diag</u>(*String* <u>message</u>)
|
||||||
Prints a diagnostic message.
|
Prints a diagnostic message.
|
||||||
|
|
|
@ -38,6 +38,9 @@ func _initialize() -> void: initialized = true
|
||||||
## Use this function to remove any children from the SceneTree and free any nodes.[br]
|
## Use this function to remove any children from the SceneTree and free any nodes.[br]
|
||||||
## If not done you might cause a memory leak.
|
## If not done you might cause a memory leak.
|
||||||
func _cleanup() -> void: pass
|
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]
|
## Called after CORE's configuration got updated.[br]
|
||||||
## Probably useless to your module, unless you want to modify another module's settings.
|
## Probably useless to your module, unless you want to modify another module's settings.
|
||||||
func _pull_config() -> void: pass
|
func _pull_config() -> void: pass
|
||||||
|
|
|
@ -28,14 +28,18 @@ class_name CoreLoggerInstance
|
||||||
var logger: CoreBaseModule
|
var logger: CoreBaseModule
|
||||||
## The origin argument.
|
## The origin argument.
|
||||||
var origin: String
|
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]
|
## [b]Note: [i]Don't modify.[/i][/b]
|
||||||
var framework: bool = false
|
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.
|
## 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
|
logger = logger_new
|
||||||
origin = origin_new
|
origin = origin_new
|
||||||
|
parent = parent_new
|
||||||
|
|
||||||
## Prints a diagnostic message.
|
## Prints a diagnostic message.
|
||||||
func diag(message: String) -> void: logger.diag(origin, message)
|
func diag(message: String) -> void: logger.diag(origin, message)
|
||||||
|
|
82
src/core.gd
82
src/core.gd
|
@ -36,6 +36,10 @@ const modules: Array[String] = [ "logger", "misc", "sms", "logui", "erm", "stora
|
||||||
## CORE's configuration object.[br]
|
## CORE's configuration object.[br]
|
||||||
## [b]NEVER access this yourself! To change the configuration use [method reload_configuration] instead.[/b]
|
## [b]NEVER access this yourself! To change the configuration use [method reload_configuration] instead.[/b]
|
||||||
var config: CoreConfiguration
|
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
|
## The 'Logger' module
|
||||||
var logger: CoreBaseModule
|
var logger: CoreBaseModule
|
||||||
## The 'Miscellaneous' module
|
## The 'Miscellaneous' module
|
||||||
|
@ -73,6 +77,7 @@ func _init(new_config: CoreConfiguration = CoreConfiguration.new()) -> void:
|
||||||
reload_configuration(new_config)
|
reload_configuration(new_config)
|
||||||
initialize_modules()
|
initialize_modules()
|
||||||
apply_configuration()
|
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]
|
## 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]
|
## [b]Danger: [i]Don't call this.[/i][/b]
|
||||||
|
@ -80,7 +85,8 @@ func _ready() -> void:
|
||||||
inject_modules()
|
inject_modules()
|
||||||
custom_modules_node.name = "Custom Modules"
|
custom_modules_node.name = "Custom Modules"
|
||||||
add_child(custom_modules_node)
|
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]
|
## Initializes all built-in modules during the preinitialization phase.[br]
|
||||||
## [b]Danger: [i]Don't call this.[/i][/b]
|
## [b]Danger: [i]Don't call this.[/i][/b]
|
||||||
|
@ -90,13 +96,29 @@ 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).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.[br]
|
||||||
## [b]Danger: [i]Don't call this.[/i][/b]
|
## [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.
|
||||||
|
## [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]
|
## Waits for all modules to fully initialize.[br]
|
||||||
## [br]
|
## [br]
|
||||||
## This ensures that all modules are fully initialized and ready for usage.[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
|
await get_tree().process_frame
|
||||||
if !no_success_message: loggeri.info("Initialized CORE successfully")
|
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 +++
|
# +++ custom module support +++
|
||||||
## Registers a new custom module.
|
## Registers a new custom module.
|
||||||
func register_custom_module(module_name: String, module_origin: String, module_class: CoreBaseModule) -> bool:
|
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")
|
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.loggeri = logger.get_instance(module_origin, module_class)
|
||||||
module_class.loggeri.framework = true
|
module_class.loggeri.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)
|
||||||
|
@ -175,33 +224,6 @@ func get_custom_module(module_name: String) -> CoreBaseModule:
|
||||||
return null
|
return null
|
||||||
return custom_modules[module_name]
|
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 ++
|
# +++ etc ++
|
||||||
## 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.
|
||||||
|
|
|
@ -23,6 +23,11 @@ extends CoreBaseModule
|
||||||
|
|
||||||
signal log_event
|
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.
|
## The minimum log level you want to be displayed.
|
||||||
var config_level: CoreTypes.LoggerLevel
|
var config_level: CoreTypes.LoggerLevel
|
||||||
## Determines if the logger's output should be colored.
|
## Determines if the logger's output should be colored.
|
||||||
|
@ -36,6 +41,14 @@ var config_newlines_override: bool
|
||||||
var config_newlines_sizelimit: int
|
var config_newlines_sizelimit: int
|
||||||
|
|
||||||
# +++ module +++
|
# +++ 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:
|
func _pull_config() -> void:
|
||||||
config_level = core.config.logger_level
|
config_level = core.config.logger_level
|
||||||
config_colored = core.config.logger_colored
|
config_colored = core.config.logger_colored
|
||||||
|
@ -203,4 +216,8 @@ func is_level_allowed(level: CoreTypes.LoggerLevel) -> bool:
|
||||||
else: return false
|
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.
|
## 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
|
||||||
|
|
Loading…
Reference in a new issue