2024-02-12 19:47:28 +01:00
# CORE FRAMEWORK SOURCE FILE
# Copyright (c) 2024 The StarOpenSource Project & Contributors
2024-03-03 18:53:09 +01:00
# Licensed under the GNU Affero General Public License v3
2024-02-12 19:47:28 +01:00
#
# This program is free software: you can redistribute it and/or modify
2024-03-03 18:53:09 +01:00
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
2024-02-12 19:47:28 +01:00
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2024-03-03 18:53:09 +01:00
# GNU Affero General Public License for more details.
2024-02-12 19:47:28 +01:00
#
2024-03-03 18:53:09 +01:00
# You should have received a copy of the GNU Affero General Public License
2024-02-12 19:47:28 +01:00
# along with this program. If not, see <https://www.gnu.org/licenses/>.
## Initializes and manages the framework.
##
## The [b]CORE Object[/b] is responsible for initializing, managing and
2024-04-08 02:43:31 +02:00
## serving the CORE Framework.
2024-02-04 21:36:30 +01:00
extends Node
class_name Core
2024-04-08 02:43:31 +02:00
# Versioning
2024-03-28 12:54:12 +01:00
## The version number
const version_version : int = 1
2024-04-08 02:43:31 +02:00
## The version type. See [enum CoreTypes.VersionType] for more information.
2024-04-14 14:52:19 +02:00
const version_type : CoreTypes . VersionType = CoreTypes . VersionType . RELEASE
2024-03-28 12:54:12 +01:00
## The version type number. Resets on every new version and version type.
2024-04-14 15:18:21 +02:00
const version_typerelease : int = 1
2024-04-26 19:54:16 +02:00
## The fork indicator. Update this if you intend on soft or hard forking this framework.
const version_fork : String = " "
2024-02-04 21:36:30 +01:00
# Modules
2024-04-08 02:43:31 +02:00
## Used internally for loading, managing and unloading modules.
2024-05-03 21:28:07 +02:00
const modules : Array [ String ] = [ " logger " , " misc " , " sms " , " logui " , " erm " , " storage " , " validation " ]
2024-04-08 02:43:31 +02:00
## CORE's configuration object.[br]
## [b]NEVER access this yourself! To change the configuration use [method reload_configuration] instead.[/b]
var config : CoreConfiguration
2024-04-09 20:13:49 +02:00
## The framework scheduler.[br]
## Performs various maintenance tasks every minute.
## [b]Danger: [i]Don't modify this.[/i][/b]
var scheduler : Timer
2024-04-08 02:43:31 +02:00
## The 'Logger' module
2024-02-04 21:36:30 +01:00
var logger : CoreBaseModule
2024-04-08 02:43:31 +02:00
## The 'Miscellaneous' module
2024-02-04 21:36:30 +01:00
var misc : CoreBaseModule
2024-04-08 02:43:31 +02:00
## The 'Scene Management System' module
2024-02-09 21:18:14 +01:00
var sms : CoreBaseModule
2024-04-08 02:43:31 +02:00
## The 'Log UI' module. Not important for you, it just displays the log graphically :3
2024-02-04 21:36:30 +01:00
var logui : CoreBaseModule
2024-04-08 02:43:31 +02:00
## The 'Easy Request Maker' module (formerly 'Easy DownLoader')
2024-03-31 17:35:09 +02:00
var erm : CoreBaseModule
2024-04-08 02:43:31 +02:00
## The 'Storage' module
2024-03-18 03:23:27 +01:00
var storage : CoreBaseModule
2024-05-03 21:28:07 +02:00
## The 'Data Validation' module
var validation : CoreBaseModule
2024-02-04 21:36:30 +01:00
2024-04-08 02:43:31 +02:00
# /etc/
## Stores the path to CORE's installation directory.[br]
2024-04-08 21:19:24 +02:00
## [b]Danger: [i]Don't modify this.[/i][/b]
2024-02-04 21:36:30 +01:00
var basepath : String
2024-04-15 00:07:25 +02:00
# Contains a list of all registered cleanup hooks.
2024-04-14 23:48:53 +02:00
var cleanup_hooks : Dictionary = { }
2024-04-23 21:02:38 +02:00
## Internal, don't modify.
2024-04-15 00:07:25 +02:00
# Contains a list of all loaded custom modules.
2024-02-05 18:03:16 +01:00
var custom_modules : Dictionary = { }
2024-04-23 21:02:38 +02:00
## Internal, don't modify.
2024-04-15 00:07:25 +02:00
# Contains the node holding all custom modules as children.
2024-02-09 15:30:20 +01:00
var custom_modules_node : Node
2024-04-23 21:02:38 +02:00
## Internal, don't modify.
2024-04-15 00:07:25 +02:00
# The CORE Object's logger instance.
2024-04-08 21:30:24 +02:00
var loggeri : CoreLoggerInstance
2024-04-23 21:02:38 +02:00
## Internal, don't modify.
# Makes CORE inaccessible if true.
var disabled : bool = false
2024-04-23 21:34:38 +02:00
## Internal, don't modify.
# Displays the ✨ special ✨ welcome message if true
var welcomed : bool = false
2024-02-04 21:36:30 +01:00
2024-04-24 01:41:46 +02:00
## Contains the amount of time it took to preinitialize the framework, measured in milliseconds.[br]
## Captured in [method _init].[br]
## [b]Danger: [i]Don't modify this.[/i][/b]
var initduration_preinitialization : int = 0
## Contains the amount of time it took to initialize the framework, measured in milliseconds.[br]
## Captured in [method _ready].[br]
## [b]Danger: [i]Don't modify this.[/i][/b]
var initduration_initialization : int = 0
## Contains the amount of time it took to completely initialize the framework, measured in milliseconds.[br]
## Captured in [method complete_init].[br]
## [b]Danger: [i]Don't modify this.[/i][/b]
var initduration_complete_initialization : int = 0
2024-04-08 02:43:31 +02:00
# +++ initialization +++
2024-05-03 21:26:42 +02:00
# Preinitialization
2024-02-04 21:36:30 +01:00
func _init ( new_config : CoreConfiguration = CoreConfiguration . new ( ) ) - > void :
2024-04-24 01:41:46 +02:00
var inittime : int = Time . get_ticks_msec ( )
2024-02-04 21:36:30 +01:00
name = " CORE "
2024-03-03 19:08:20 +01:00
if ! check_godot_version ( ) : return
2024-05-10 21:19:27 +02:00
if ! determine_basepath ( ) :
get_tree ( ) . quit ( 70 )
while true : await get_tree ( ) . create_timer ( 9999 ) . timeout
2024-02-09 15:30:20 +01:00
custom_modules_node = Node . new ( )
2024-02-04 21:36:30 +01:00
reload_configuration ( new_config )
initialize_modules ( )
apply_configuration ( )
2024-04-09 20:13:49 +02:00
initialize_scheduler ( )
2024-04-24 01:41:46 +02:00
initduration_preinitialization = Time . get_ticks_msec ( ) - inittime
2024-02-04 21:36:30 +01:00
2024-05-03 21:26:42 +02:00
# Initialization
2024-02-04 21:36:30 +01:00
func _ready ( ) - > void :
2024-04-24 01:41:46 +02:00
var inittime : int = Time . get_ticks_msec ( )
2024-02-04 21:36:30 +01:00
inject_modules ( )
2024-02-09 22:59:43 +01:00
custom_modules_node . name = " Custom Modules "
2024-02-09 15:30:20 +01:00
add_child ( custom_modules_node )
2024-04-09 20:13:49 +02:00
loggeri = logger . get_instance ( basepath . replace ( " res:// " , " " ) + " src/core.gd " , self )
add_child ( scheduler )
2024-04-14 14:23:05 +02:00
get_tree ( ) . auto_accept_quit = false
2024-04-24 01:41:46 +02:00
initduration_initialization = Time . get_ticks_msec ( ) - inittime
2024-02-04 21:36:30 +01:00
2024-04-15 00:07:25 +02:00
# Initializes all built-in modules during the preinitialization phase.
2024-04-23 21:02:38 +02:00
## Internal, don't call.
2024-02-04 21:36:30 +01:00
func initialize_modules ( ) - > void :
2024-03-29 02:40:56 +01:00
for module in modules :
set ( module , CoreBaseModule . new ( ) )
get ( module ) . name = module
get ( module ) . set_script ( load ( basepath + " src/ " + module + " .gd " ) )
get ( module ) . core = self
2024-04-25 20:20:34 +02:00
get ( module ) . logger = logger . get_instance ( basepath . replace ( " res:// " , " " ) + " src/ " + module + " .gd " , get ( module ) )
2024-03-29 02:40:56 +01:00
get ( module ) . _initialize ( )
2024-02-04 21:36:30 +01:00
2024-04-15 00:07:25 +02:00
# Injects CORE's builtin modules into the SceneTree.
2024-04-23 21:02:38 +02:00
## Internal, don't call.
2024-03-29 02:40:56 +01:00
func inject_modules ( ) - > void : for module in modules : add_child ( get ( module ) )
2024-02-04 21:36:30 +01:00
2024-04-15 00:07:25 +02:00
# Initializes the framework scheduler.
2024-04-23 21:02:38 +02:00
## Internal, don't call.
2024-04-09 20:13:49 +02:00
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 " )
2024-05-11 12:17:21 +02:00
var modules_reverse : Array [ String ] = modules . duplicate ( )
modules_reverse . reverse ( )
for module in modules_reverse : await get ( module ) . _schedule ( )
2024-04-09 20:13:49 +02:00
for module in custom_modules_node . get_children ( ) : await module . _schedule ( )
)
2024-04-08 02:43:31 +02:00
## Waits for all modules to fully initialize.[br]
2024-03-22 21:12:11 +01:00
## [br]
2024-04-08 02:43:31 +02:00
## This ensures that all modules are fully initialized and ready for usage.[br]
## [i][b]Not calling this function during startup may lead to runtime issues.[/b][/i]
2024-04-23 21:34:38 +02:00
func complete_init ( ) - > void :
2024-04-24 01:41:46 +02:00
var inittime : int = Time . get_ticks_msec ( )
2024-04-25 20:20:34 +02:00
var modsinit_builtin : Array [ String ] = [ " workaround " ]
var modsinit_custom : Array [ String ] = [ " workaround " ]
2024-03-22 21:12:11 +01:00
while modsinit_builtin . size ( ) != 0 and modsinit_custom . size ( ) != 0 :
# Clear arrays
modsinit_builtin = [ ]
modsinit_custom = [ ]
# Check builtin modules
2024-03-29 02:40:56 +01:00
for module in modules : if ! get ( module ) . initialized : modsinit_builtin . append ( module )
2024-03-22 21:12:11 +01:00
# Check custom modules
for module_name in custom_modules :
if ! custom_modules [ module_name ] . initialized : modsinit_custom . append ( module_name )
# Print and sleep
if modsinit_builtin . size ( ) != 0 or modsinit_custom . size ( ) != 0 :
print ( " Waiting for modules to finish initialization: " )
2024-04-14 14:42:46 +02:00
if modsinit_builtin . size ( ) != 0 : print ( " Built-in: " + str ( modsinit_builtin ) )
2024-03-29 02:40:56 +01:00
if modsinit_custom . size ( ) != 0 : print ( " Custom: " + str ( modsinit_custom ) )
2024-03-22 21:12:11 +01:00
await get_tree ( ) . create_timer ( 1 ) . timeout
# Initialization complete
await get_tree ( ) . process_frame
2024-04-23 21:34:38 +02:00
if ! welcomed :
welcomed = true
2024-04-26 19:55:16 +02:00
var version_welcome : String = await get_formatted_string ( " v % version %-% version_type_technical %% version_typerelease %% version_fork % " )
if version_welcome . length ( ) > 15 :
await logger . crash ( " Invalid version size of 15 " )
elif version_welcome . length ( ) < 15 :
version_welcome = " " . repeat ( 15 - version_welcome . length ( ) ) + version_welcome
logger . _log ( CoreTypes . LoggerLevel . SPECIAL , basepath . replace ( " res:// " , " " ) + " src/core.gd " , """ _________________________________ __________ % version % ______
2024-04-23 21:34:38 +02:00
__ ____ / _ __ \\__ __ \\__ ____ / ___ ____ / ____________ _______ ___________ _________________ / __
_ / _ / / / _ / _ / / _ __ / __ / _ __ ___ / __ ` / _ __ ` __ \\ _ \\_ | / | / / __ \\_ ___ / _ / / _ /
/ / ___ / / _ / / _ _ , _ / _ / ___ _ __ / _ / / / _ / / _ / / / / / __ / _ | / | / / / / _ / / / _ , <
\\____ / \\____ / / _ / | _ | / _____ / / _ / / _ / \\__ , _ / / _ / / _ / / _ / \\___ / ____ / | __ / \\____ / / _ / / _ / | _ |
Copyright ( c ) 2023 - 2024 The StarOpenSource Project & Contributors .
Licensed under the GNU Affero General Public License v3 WITHOUT ANY WARRANTY .
You should have recieved a copy of the GNU Affero General Public License
along with this program . If not , see < https : / / www . gnu . org / licenses / > .
Consider contributing to the CORE Framework to make it even better . . . and remember : #TransRightsAreHumanRights
2024-04-26 19:55:16 +02:00
Thank you for using the CORE Framework to develop your application or game ! """ .replace( " % version % " , version_welcome))
2024-04-24 01:40:21 +02:00
if is_devmode ( ) : loggeri . warn ( " The CORE Framework is running in development mode. \n This may cause bugs and issues inside the framework. Here be dragons! " )
if logger . verbose_mode : loggeri . warn ( " Godot is running in verbose stdout mode. \n Due to a bug in the engine that prevents displaying truecolor ANSI escape \n sequences CORE changed the color of all diagnostic log messages. \n To prevent this, set ' logger_detect_verbose_mode ' in the configuration to ' false ' . " )
2024-04-26 19:55:16 +02:00
initduration_complete_initialization = Time . get_ticks_msec ( ) - inittime
loggeri . info ( " Framework initialization took " + str ( initduration_preinitialization + initduration_initialization + initduration_complete_initialization ) + " ms (pre " + str ( initduration_preinitialization ) + " ms, init " + str ( initduration_initialization ) + " ms, complete " + str ( initduration_complete_initialization ) + " ms) " )
2024-03-22 21:12:11 +01:00
2024-04-09 20:13:49 +02:00
# +++ 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 " )
2024-05-10 19:16:25 +02:00
if is_instance_valid ( config ) : config . free ( )
2024-04-12 16:59:29 +02:00
config = new_config . duplicate ( )
2024-04-09 20:13:49 +02:00
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 ( )
2024-04-15 00:07:25 +02:00
# Applies a new configuration.
2024-04-23 21:02:38 +02:00
## Internal, don't call.
2024-04-09 20:13:49 +02:00
func apply_configuration ( ) - > void :
if loggeri != null : loggeri . verb ( " Applying configuration " )
2024-04-10 21:34:12 +02:00
if is_devmode ( ) and loggeri != null : loggeri . warn ( " The CORE Framework is in development mode. Here be dragons! " )
2024-04-09 20:13:49 +02:00
if ! config . custom_modules :
2024-04-12 15:48:17 +02:00
if loggeri != null : loggeri . diag ( " Removing all custom modules (custom modules support is disabled) " )
2024-04-09 20:13:49 +02:00
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 :
2024-04-12 15:48:17 +02:00
custom_modules [ module ] . _pull_config ( )
2024-04-14 15:17:55 +02:00
# Workaround
2024-04-24 01:39:38 +02:00
if config . logger_detect_verbose_mode : logger . verbose_mode = OS . is_stdout_verbose ( )
2024-04-09 20:13:49 +02:00
2024-04-08 02:43:31 +02:00
# +++ custom module support +++
2024-02-12 19:47:28 +01:00
## Registers a new custom module.
2024-03-31 11:22:57 +02:00
func register_custom_module ( module_name : String , module_origin : String , module_class : CoreBaseModule ) - > bool :
2024-04-08 21:30:24 +02:00
loggeri . verb ( " Registering new custom module \" " + module_name + " \" " )
2024-02-10 18:49:25 +01:00
if ! config . custom_modules :
2024-04-08 21:30:24 +02:00
loggeri . error ( " Registering module failed: Custom module support is disabled. " )
2024-02-10 18:49:25 +01:00
return false
2024-02-05 18:03:16 +01:00
if custom_modules . has ( module_name ) :
2024-04-25 20:20:34 +02:00
loggeri . error ( stringify_variables ( " Registering module failed: A custom module with the name % name % already exists. " , { " name " : module_name } ) )
2024-02-10 18:49:25 +01:00
return false
2024-04-08 21:30:24 +02:00
loggeri . diag ( " Updating variables " )
2024-03-31 11:22:57 +02:00
module_class . name = module_name
2024-03-22 21:41:27 +01:00
module_class . core = self
2024-05-07 17:02:41 +02:00
module_class . logger = logger . get_instance ( module_origin , module_class )
2024-04-25 20:20:34 +02:00
module_class . logger . framework = true
2024-04-08 21:30:24 +02:00
loggeri . diag ( " Adding module to SceneTree " )
2024-02-09 15:30:20 +01:00
custom_modules_node . add_child ( module_class )
2024-04-08 21:30:24 +02:00
loggeri . diag ( " Merging module with custom_modules " )
2024-02-05 18:03:16 +01:00
custom_modules . merge ( { module_name : module_class } )
2024-04-08 21:30:24 +02:00
loggeri . diag ( " Initializing custom module " )
2024-02-05 18:03:16 +01:00
module_class . _initialize ( )
2024-04-08 21:30:24 +02:00
loggeri . diag ( " Updating custom module configuration " )
2024-02-05 18:03:16 +01:00
module_class . _pull_config ( )
2024-02-10 18:49:25 +01:00
return true
2024-02-05 18:03:16 +01:00
2024-04-08 02:43:31 +02:00
## Unregisters a custom module, making it no longer available.
2024-02-05 18:03:16 +01:00
func unregister_custom_module ( module_name : String ) - > void :
2024-04-08 21:30:24 +02:00
loggeri . verb ( " Unregistering custom module \" " + module_name + " \" " )
2024-02-05 18:03:16 +01:00
if ! custom_modules . has ( module_name ) :
2024-04-25 20:20:34 +02:00
loggeri . error ( stringify_variables ( " Unregistering module failed: A custom module with the name % name % d oes not exist. " , { " name " : module_name } ) )
2024-02-05 18:03:16 +01:00
return
2024-04-14 19:58:48 +02:00
var module : Node = custom_modules [ module_name ]
2024-03-29 02:40:56 +01:00
await module . _cleanup ( )
2024-04-25 20:20:34 +02:00
module . logger . queue_free ( )
2024-03-29 02:40:56 +01:00
custom_modules_node . remove_child ( module )
2024-02-05 18:03:16 +01:00
custom_modules . erase ( module_name )
2024-03-29 02:40:56 +01:00
module . queue_free ( )
2024-02-05 18:03:16 +01:00
2024-04-08 02:43:31 +02:00
## Returns a registered custom module.[br]
## Please note that you can't get CORE's built-in modules with this function.
2024-02-05 18:03:16 +01:00
func get_custom_module ( module_name : String ) - > CoreBaseModule :
2024-04-08 21:30:24 +02:00
loggeri . diag ( " Getting custom module \" " + module_name + " \" " )
2024-02-05 18:03:16 +01:00
if ! custom_modules . has ( module_name ) :
2024-04-25 20:20:34 +02:00
loggeri . error ( stringify_variables ( " Getting module failed: A custom module with the name % name % d oes not exist. " , { " name " : module_name } ) )
2024-03-22 21:41:27 +01:00
return null
2024-02-05 18:03:16 +01:00
return custom_modules [ module_name ]
2024-04-14 23:48:53 +02:00
# +++ cleanup ++
2024-04-08 02:43:31 +02:00
## Makes sure that CORE does not leak memory on shutdown/unload.[br]
2024-04-14 23:48:53 +02:00
## 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.
2024-04-08 02:43:31 +02:00
func cleanup ( ) - > void :
2024-04-08 21:30:24 +02:00
loggeri . info ( " Cleaning up " )
2024-04-14 23:48:53 +02:00
loggeri . verb ( " Calling cleanup hooks " )
for hook in cleanup_hooks :
if ! cleanup_hooks [ hook ] . is_valid ( ) :
2024-04-25 20:20:34 +02:00
loggeri . error ( stringify_variables ( " Cleanup hook %i d % i s invalid " , { " id " : hook } ) )
2024-04-14 23:48:53 +02:00
else :
loggeri . diag ( " Calling cleanup hook # " + str ( hook ) )
await cleanup_hooks [ hook ] . call ( )
2024-05-10 19:16:25 +02:00
await get_tree ( ) . process_frame
2024-04-14 23:48:53 +02:00
loggeri . verb ( " Unregistering custom modules " )
2024-04-14 19:58:48 +02:00
for module in custom_modules_node . get_children ( ) : await unregister_custom_module ( module . name )
2024-05-10 19:16:25 +02:00
await get_tree ( ) . process_frame
2024-04-14 23:48:53 +02:00
loggeri . verb ( " Removing custom module support " )
2024-04-12 17:03:37 +02:00
remove_child ( custom_modules_node )
custom_modules_node . queue_free ( )
2024-05-10 19:16:25 +02:00
await get_tree ( ) . process_frame
2024-04-14 23:48:53 +02:00
loggeri . verb ( " Unloading built-in modules " )
2024-04-08 02:43:31 +02:00
var modules_reverse : Array [ String ] = modules . duplicate ( )
modules_reverse . reverse ( )
for module in modules_reverse :
await get ( module ) . _cleanup ( )
get ( module ) . queue_free ( )
2024-04-14 19:58:48 +02:00
await get_tree ( ) . process_frame
2024-05-10 19:16:25 +02:00
print ( " Freeing configuration " )
config . free ( )
2024-04-14 23:48:53 +02:00
print ( " Freeing " )
2024-04-08 02:43:31 +02:00
queue_free ( )
2024-04-14 23:48:53 +02:00
# Generates a new cleanup hook id
2024-04-23 21:02:38 +02:00
## Internal, don't call.
2024-04-14 23:48:53 +02:00
func _generate_hook_id ( ) - > int :
var id = randi ( )
if cleanup_hooks . has ( id ) :
2024-04-25 20:20:34 +02:00
loggeri . warn ( stringify_variables ( " New cleanup hook id %i d % i s already taken " , { " id " : id } ) )
2024-04-14 23:48:53 +02:00
return _generate_hook_id ( )
elif id == - 1 :
2024-04-25 20:20:34 +02:00
loggeri . warn ( stringify_variables ( " Invalid cleanup hook id %i d % " , { " id " : id } ) )
2024-04-14 23:48:53 +02:00
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 ) :
2024-04-25 20:20:34 +02:00
loggeri . error ( stringify_variables ( " Could not remove cleanup hook (id): Hook %i d % d oes not exist " , { " id " : id } ) )
2024-04-14 23:48:53 +02:00
return false
2024-04-25 20:20:34 +02:00
loggeri . verb ( stringify_variables ( " Removed cleanup hook %i d % " , { " id " : id } ) )
2024-04-14 23:48:53 +02:00
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
2024-04-25 20:20:34 +02:00
if typeof ( id ) != TYPE_INT : await loggeri . crash ( stringify_variables ( " Could not remove cleanup hook (ref): find_key did not return an integer (returned %i d % ) " , { " id " : id } ) )
2024-04-14 23:48:53 +02:00
cleanup_hooks . erase ( id )
2024-04-25 20:20:34 +02:00
loggeri . verb ( stringify_variables ( " Removed cleanup hook %i d % (ref) " , { " id " : id } ) )
2024-04-14 23:48:53 +02:00
return true
# +++ etc +++
2024-04-09 00:53:43 +02:00
## Returns if the framework is in development mode.
2024-02-04 21:36:30 +01:00
func is_devmode ( ) - > bool :
2024-04-09 00:53:43 +02:00
return config . development
2024-02-04 21:36:30 +01:00
2024-04-08 02:43:31 +02:00
## Replaces placeholders with human-friendly strings.[br]
## You can use the following placeholders:[br]
## - [code]%version%[/code]: Returns the version number.[br]
## - [code]%version_type%[/code]: Returns the version type number[br]
## - [code]%version_semantic%[/code]: Returns the result of [method Core.get_version_semantic], example [i]5.2.3[/i][br]
## - [code]%version_type%[/code]: Returns the version type as a word, for example [i]Release Candidate[/i][br]
## - [code]%version_type_technical%[/code]: Returns the version type as one or two lowercase letters, for example [i]rc[/i][br]
2024-03-03 19:08:40 +01:00
## - [code]%devmode%[/code]: Returns the development mode status[br]
2024-04-08 02:43:31 +02:00
## - [code]%headless%[/code]: Returns the headless mode status[br]
## - [code]%custommodules%[/code]: Returns if custom module support is enabled
2024-02-04 21:36:30 +01:00
func get_formatted_string ( string : String ) - > String :
# Version strings
2024-03-28 12:54:12 +01:00
string = string . replace ( " % version % " , str ( version_version ) )
2024-04-08 20:18:49 +02:00
string = string . replace ( " % version_typerelease % " , str ( version_typerelease ) )
2024-04-26 19:54:16 +02:00
string = string . replace ( " % version_fork % " , " " if version_fork == " " else " - " + version_fork )
2024-02-04 21:36:30 +01:00
var semantic_version : Array [ int ] = get_version_semantic ( )
2024-03-28 12:54:12 +01:00
string = string . replace ( " % version_semantic % " , str ( semantic_version [ 0 ] ) + " . " + str ( semantic_version [ 1 ] ) + " . " + str ( semantic_version [ 2 ] ) )
2024-02-04 21:36:30 +01:00
match ( version_type ) :
CoreTypes . VersionType . RELEASE :
2024-04-08 02:43:31 +02:00
string = string . replace ( " % version_type % " , " Release " )
string = string . replace ( " % version_type_technical % " , " r " )
2024-02-04 21:36:30 +01:00
CoreTypes . VersionType . RELEASECANDIDATE :
2024-04-08 02:43:31 +02:00
string = string . replace ( " % version_type % " , " Release Candidate " )
string = string . replace ( " % version_type_technical % " , " rc " )
2024-02-04 21:36:30 +01:00
CoreTypes . VersionType . BETA :
2024-04-08 02:43:31 +02:00
string = string . replace ( " % version_type % " , " Beta " )
string = string . replace ( " % version_type_technical % " , " b " )
2024-02-04 21:36:30 +01:00
CoreTypes . VersionType . ALPHA :
2024-04-08 02:43:31 +02:00
string = string . replace ( " % version_type % " , " Alpha " )
string = string . replace ( " % version_type_technical % " , " a " )
2024-04-08 21:30:24 +02:00
_ : await loggeri . crash ( " Invalid version type " + str ( version_type ) )
2024-02-04 21:36:30 +01:00
# Development mode
if is_devmode ( ) : string = string . replace ( " %d evmode % " , " Enabled " )
else : string = string . replace ( " %d evmode % " , " Disabled " )
# Headless mode
if config . headless : string = string . replace ( " %he adless % " , " Enabled " )
else : string = string . replace ( " %he adless % " , " Disabled " )
2024-02-10 18:49:25 +01:00
# Custom module support
if config . custom_modules : string = string . replace ( " %c ustommodules % " , " Enabled " )
else : string = string . replace ( " %c ustommodules % " , " Disabled " )
2024-02-04 21:36:30 +01:00
return string
2024-02-12 19:47:28 +01:00
## Returns CORE's versioning scheme into the semantic versioning scheme.[br]
2024-04-08 02:43:31 +02:00
## The first integer contains the version number, the second integer contains the version type ([code]0[/code] for alpha, [code]1[/code] for beta, [code]2[/code] for rc and [code]3[/code] for release and the last integer contains the version type number.
2024-02-04 21:36:30 +01:00
func get_version_semantic ( ) - > Array [ int ] :
var version_type_int : int
match ( version_type ) :
CoreTypes . VersionType . RELEASE : version_type_int = 3
CoreTypes . VersionType . RELEASECANDIDATE : version_type_int = 2
CoreTypes . VersionType . BETA : version_type_int = 1
CoreTypes . VersionType . ALPHA : version_type_int = 0
2024-03-28 12:54:12 +01:00
return [ version_version , version_type_int , version_typerelease ]
2024-02-12 19:56:17 +01:00
2024-04-15 00:07:25 +02:00
# Determines CORE's installation/base path.
2024-02-12 19:56:17 +01:00
func determine_basepath ( ) - > bool :
if FileAccess . file_exists ( " res://.corebasepath " ) :
basepath = " res:// "
elif FileAccess . file_exists ( " res://CORE/.corebasepath " ) :
basepath = " res://CORE/ "
elif FileAccess . file_exists ( " res://addons/CORE/.corebasepath " ) :
basepath = " res://addons/CORE/ "
else :
2024-04-23 21:33:02 +02:00
printerr ( " CORE is not located at ' res://CORE/ ' or ' res://addons/CORE ' , aborting initialization. " )
2024-02-12 19:56:17 +01:00
return false
return true
## Checks compatibility with the running version.
func check_godot_version ( ) - > bool :
var version : Dictionary = Engine . get_version_info ( )
match ( version [ " major " ] ) :
4 : pass
_ :
2024-04-23 21:33:02 +02:00
printerr ( " The CORE Framework does not support Godot versions older or newer than 4.x.x. " )
2024-03-03 19:08:20 +01:00
return false
2024-02-12 19:56:17 +01:00
match ( version [ " minor " ] ) :
2024-03-03 19:08:20 +01:00
0 : printerr ( " The CORE Framework does not support Godot versions older than 4.2.x. Please update to Godot 4.2.x to ensure full compatibility. " )
1 : printerr ( " The CORE Framework does not support Godot versions older than 4.2.x. Please update to Godot 4.2.x to ensure full compatibility. " )
2024-02-12 19:56:17 +01:00
2 : pass
2024-03-03 19:08:20 +01:00
_ :
printerr ( " The CORE Framework does not support Godot versions newer than 4.2.x. Please downgrade to Godot 4.2.x. " )
return false
if version [ " status " ] != " stable " :
2024-04-23 21:33:02 +02:00
printerr ( " The CORE Framework does not support unstable Godot versions. Please switch to Godot 4.2.x.stable to ensure full compatibility. " )
2024-03-03 19:08:20 +01:00
return false
2024-02-12 19:56:17 +01:00
return true
2024-04-08 21:42:03 +02:00
## Makes sure for all log messages to be flushed and that CORE is correctly cleaned up.[br]
## Using [method SceneTree.quit] directly may cause various issues.[br]
## [b]Note: [i]Using the [code]await[/code] keyword is required for this function.[/i][/b]
func quit_safely ( exitcode : int = 0 ) - > void :
loggeri . info ( " Shutting down (code " + str ( exitcode ) + " ) " )
2024-04-24 01:41:21 +02:00
if config . hide_window_on_shutdown :
loggeri . verb ( " Hiding window " )
Engine . max_fps = - 1 # a higher framerate seems to make the shutdown process muuuuch faster
DisplayServer . window_set_vsync_mode ( DisplayServer . VSYNC_ENABLED ) # we don't want to cook the cpu tho
DisplayServer . window_set_exclusive ( 0 , false )
DisplayServer . window_set_mode ( DisplayServer . WINDOW_MODE_MINIMIZED )
DisplayServer . window_set_min_size ( Vector2 . ZERO )
DisplayServer . window_set_size ( Vector2i . ZERO )
DisplayServer . window_set_max_size ( Vector2 . ZERO )
DisplayServer . window_set_position ( Vector2i ( 9999999 , 9999999 ) )
DisplayServer . window_set_flag ( DisplayServer . WINDOW_FLAG_BORDERLESS , true )
DisplayServer . window_set_flag ( DisplayServer . WINDOW_FLAG_ALWAYS_ON_TOP , false )
DisplayServer . window_set_flag ( DisplayServer . WINDOW_FLAG_MOUSE_PASSTHROUGH , false )
DisplayServer . window_set_flag ( DisplayServer . WINDOW_FLAG_NO_FOCUS , true )
DisplayServer . window_set_flag ( DisplayServer . WINDOW_FLAG_RESIZE_DISABLED , true )
2024-04-08 21:42:03 +02:00
await get_tree ( ) . create_timer ( 0.25 ) . timeout
await cleanup ( )
get_tree ( ) . quit ( exitcode )
2024-04-14 14:23:05 +02:00
2024-04-25 20:20:34 +02:00
## 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 )
2024-04-23 21:02:38 +02:00
## Internal, don't call.
2024-04-25 20:20:34 +02:00
# Just ignore this.
2024-04-14 14:23:05 +02:00
func _notification ( what ) - > void :
match ( what ) :
NOTIFICATION_WM_CLOSE_REQUEST :
if config . automatic_shutdown :
2024-04-26 19:55:16 +02:00
loggeri . diag ( " Got close request, shutting down " )
2024-04-14 14:23:05 +02:00
await quit_safely ( 0 )