diff --git a/src/classes/config.gd b/src/classes/config.gd index 132b8ae..259550c 100644 --- a/src/classes/config.gd +++ b/src/classes/config.gd @@ -17,11 +17,19 @@ class_name CoreConfiguration @export var development: bool ## Allows or disallows custom modules. @export var custom_modules: bool +## If [method Core.quit_safely] (and by extension [method Core.cleanup]) should be called when pressing the X. +@export var automatic_shutdown: bool + @export_category("Logger") ## The minimum log level you want to be displayed. @export var logger_level: CoreTypes.LoggerLevel ## Determines if the logger's output should be colored. @export var logger_colored: bool +## Determines if the logger should check if running in verbose mode (see [method OS.is_stdout_verbose]).[br] +## Comes with a huge performance penalty on startup, delaying startup by about one to two seconds.[br] +## Update [code]verbose_mode[/code] accordingly yourself if you've disabled this, or diagnostic log messages might appear messed up.[br] +## [b]Warning: [i]Updating this during runtime does nothing.[/i][/b] +@export var logger_detect_verbose_mode: bool ## The template for all log messages.[br] ## Available placeholders are: [code]%time%[/code], [code]%time_ms%[/code], [code]%level%[/code], [code]%color%[/code], [code]%message%[/code], [code]%source%[/code], [code]%source_raw%[/code], [code]%function%[/code] and [code]%line%[/code] @export var logger_format: String @@ -29,6 +37,7 @@ class_name CoreConfiguration @export var logger_newlines_override: bool ## The maximum amount of characters excluding the message before newlines are no longer idented. Set to [code]-1[/code] to disable this behaviour. @export var logger_newlines_sizelimit: int + @export_category("Log UI") ## Enables or disables Log UI. @export var logui_enabled: bool @@ -46,10 +55,12 @@ func _init() -> void: headless = false development = false custom_modules = false + automatic_shutdown = true # Logger logger_level = CoreTypes.LoggerLevel.INFO logger_colored = true + logger_detect_verbose_mode = false logger_format = "%color%[%time%] [%level% %origin%] %message%" logger_newlines_override = true logger_newlines_sizelimit = 40 diff --git a/src/core.gd b/src/core.gd index 36df126..efcda1b 100644 --- a/src/core.gd +++ b/src/core.gd @@ -26,9 +26,9 @@ class_name Core ## The version number const version_version: int = 1 ## The version type. See [enum CoreTypes.VersionType] for more information. -const version_type: CoreTypes.VersionType = CoreTypes.VersionType.RELEASECANDIDATE +const version_type: CoreTypes.VersionType = CoreTypes.VersionType.RELEASE ## The version type number. Resets on every new version and version type. -const version_typerelease: int = 1 +const version_typerelease: int = 0 # Modules ## Used internally for loading, managing and unloading modules. @@ -87,6 +87,7 @@ func _ready() -> void: add_child(custom_modules_node) loggeri = logger.get_instance(basepath.replace("res://", "") + "src/core.gd", self) add_child(scheduler) + get_tree().auto_accept_quit = false ## Initializes all built-in modules during the preinitialization phase.[br] ## [b]Danger: [i]Don't call this.[/i][/b] @@ -142,7 +143,7 @@ func complete_init(no_success_message: bool = false) -> void: # Print and sleep if modsinit_builtin.size() != 0 or modsinit_custom.size() != 0: print("Waiting for modules to finish initialization:") - if modsinit_builtin.size() != 0: print(" Builtin: " + str(modsinit_builtin)) + if modsinit_builtin.size() != 0: print(" Built-in: " + str(modsinit_builtin)) if modsinit_custom.size() != 0: print(" Custom: " + str(modsinit_custom)) await get_tree().create_timer(1).timeout @@ -156,7 +157,7 @@ func reload_configuration(new_config: CoreConfiguration = CoreConfiguration.new( var initialized = config != null if initialized: loggeri.verb("Reloading CORE's configuration") if config != null: config.queue_free() - config = new_config + config = new_config.duplicate() if is_devmode(): # Override configuration in development mode config.logger_level = CoreTypes.LoggerLevel.DIAG if initialized: loggeri.verb("Overrode configuration (development mode)") @@ -166,16 +167,14 @@ func reload_configuration(new_config: CoreConfiguration = CoreConfiguration.new( ## [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 is_devmode() and loggeri != null: loggeri.warn("The CORE Framework is in development mode. Here be dragons!") if !config.custom_modules: - if loggeri != null: loggeri.verb("Removing all custom modules (custom modules support is disabled)") + if loggeri != null: loggeri.diag("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_modules[module]._pull_config() # +++ custom module support +++ ## Registers a new custom module. @@ -229,16 +228,16 @@ func get_custom_module(module_name: String) -> CoreBaseModule: ## Unloads all custom modules, built-in modules, frees any of CORE's classes and lastly itself. func cleanup() -> void: loggeri.info("Cleaning up") - config.queue_free() + for module in custom_modules_node.get_children(): unregister_custom_module(module.name) + remove_child(custom_modules_node) + custom_modules_node.queue_free() var modules_reverse: Array[String] = modules.duplicate() modules_reverse.reverse() for module in modules_reverse: await get(module)._cleanup() get(module).loggeri.queue_free() get(module).queue_free() - for module in custom_modules_node.get_children(): unregister_custom_module(module.name) - remove_child(custom_modules_node) - custom_modules_node.queue_free() + config.queue_free() queue_free() ## Returns if the framework is in development mode. @@ -340,3 +339,9 @@ func quit_safely(exitcode: int = 0) -> void: await get_tree().create_timer(0.25).timeout await cleanup() get_tree().quit(exitcode) + +func _notification(what) -> void: + match(what): + NOTIFICATION_WM_CLOSE_REQUEST: + if config.automatic_shutdown: + await quit_safely(0) diff --git a/src/logger.gd b/src/logger.gd index f8035e0..11f9244 100644 --- a/src/logger.gd +++ b/src/logger.gd @@ -28,6 +28,10 @@ signal log_event ## [b]Danger: [i]Don't modify this.[/i][/b] var instances: Array[CoreLoggerInstance] = [] +## Used to determine if running in verbose/command line mode.[br] +## Makes diagnostic log messages display correctly (workaround for Godot's ANSI true color limitation). +var verbose_mode: bool = false + ## The minimum log level you want to be displayed. var config_level: CoreTypes.LoggerLevel ## Determines if the logger's output should be colored. @@ -41,6 +45,14 @@ var config_newlines_override: bool var config_newlines_sizelimit: int # +++ module +++ +func _initialize() -> void: + if core.config.logger_detect_verbose_mode and OS.is_stdout_verbose(): + verbose_mode = true + +func _cleanup() -> void: + _schedule() + await get_tree().process_frame + func _schedule() -> void: for instance in instances: if !is_instance_valid(instance): continue @@ -73,7 +85,8 @@ func _log(level: CoreTypes.LoggerLevel, origin: String, message: String) -> void CoreTypes.LoggerLevel.DIAG: format = format.replace("%level%", "DIAG") format_newline = format_newline.replace("%level%", "DIAG") - format = format.replace("%color%", "[color=dark_gray]") + if verbose_mode: format = format.replace("%color%", "[color=gray]") + else: format = format.replace("%color%", "[color=dark_gray]") CoreTypes.LoggerLevel.VERB: format = format.replace("%level%", "VERB") format_newline = format_newline.replace("%level%", "VERB")