2023-08-25 14:34:57 +02:00
######################################
# THE CORE FRAMEWORK #
# MADE BY THE STAROPENSOURCE PROJECT #
# AND CONTRIBUTERS (THANK YOU!) #
# #
# COPYRIGHT 2023 THE STAROPENSOURCE #
# PROJECT AND CONTRIBUTERS #
# #
# LICENSED UNDER THE GNU GENERAL #
# PUBLIC LICENSE VERSION 3 (ONLY) #
######################################
2023-08-07 14:49:12 +02:00
extends Node
2023-08-25 14:34:57 +02:00
# CORE modules
var core : Node = null
var logger : Node = null
2023-08-07 14:49:12 +02:00
2023-08-25 14:34:57 +02:00
# Configuration
2023-08-07 14:49:12 +02:00
var config_loadpath = null
var config_wanted_name = null
var config_wanted_version = null
var config_wanted_api = null
2023-08-25 14:34:57 +02:00
# Modification list
2023-08-07 14:49:12 +02:00
var modlist = [ ]
2023-08-25 14:34:57 +02:00
# Hook list
2023-08-07 14:49:12 +02:00
var hooks = { }
func load_mods ( ) - > Array :
if core . protection_mode : return [ ]
2023-08-25 14:34:57 +02:00
var errors : Array = [ ]
2023-08-07 14:49:12 +02:00
for directory in DirAccess . get_directories_at ( config_loadpath ) :
2023-08-25 14:34:57 +02:00
var return_value : String = await load_mod ( directory )
2023-08-07 14:49:12 +02:00
if return_value != " " :
errors . append ( return_value )
return errors
func load_mod ( mod_name : String ) - > String :
2023-08-25 14:34:57 +02:00
logger . info ( " CORE/cml.gd " , " Loading modification \" " + mod_name + " \" " )
2023-08-07 14:49:12 +02:00
if modlist . has ( mod_name ) :
2023-08-25 14:34:57 +02:00
logger . error ( " CORE/cml.gd " , " Modification \" " + mod_name + " \" is already loaded " )
2023-08-07 14:49:12 +02:00
if ! FileAccess . file_exists ( config_loadpath + " / " + mod_name + " / " + config_wanted_name + " .coremod " ) :
2023-08-25 14:34:57 +02:00
logger . error ( " CORE/cml.gd " , " Modification located at " + config_loadpath + " / " + mod_name + " does not contain a " + config_wanted_name + " .coremod file " )
2023-08-07 14:49:12 +02:00
return " Modification located at " + config_loadpath + " / " + mod_name + " does not contain a " + config_wanted_name + " .coremod file "
2023-08-25 14:34:57 +02:00
var modinfo_raw : FileAccess = FileAccess . open ( config_loadpath + " / " + mod_name + " / " + config_wanted_name + " .coremod " , FileAccess . READ )
var modinfo : Dictionary = JSON . parse_string ( modinfo_raw . get_as_text ( ) )
2023-08-07 14:49:12 +02:00
modinfo_raw . close ( )
if modinfo == null :
2023-08-25 14:34:57 +02:00
logger . error ( " CORE/cml.gd " , " Failed modinfo parsing for modification located at " + config_loadpath + " / " + mod_name )
2023-08-07 14:49:12 +02:00
return " Failed modinfo parsing for modification located at " + config_loadpath + " / " + mod_name
if ! modinfo . has_all ( [ " wanted " , " mod " ] ) :
2023-08-25 14:34:57 +02:00
logger . error ( " CORE/cml.gd " , " The modinfo of modification located at " + config_loadpath + " / " + mod_name + " does not contain wanted, mod or both " )
2023-08-07 14:49:12 +02:00
return " The modinfo of modification located at " + config_loadpath + " / " + mod_name + " does not contain wanted, mod or both "
if ! modinfo [ " wanted " ] . has_all ( [ " min_version " , " max_version " , " min_api " , " max_api " ] ) :
2023-08-25 14:34:57 +02:00
logger . error ( " CORE/cml.gd " , " The modinfo of modification located at " + config_loadpath + " / " + mod_name + " does not contain wanted.min_version, wanted.max_version, wanted.min_api or wanted.max_api or some combination of them. " )
2023-08-07 14:49:12 +02:00
return " The modinfo of modification located at " + config_loadpath + " / " + mod_name + " does not contain wanted.min_version, wanted.max_version, wanted.min_api or wanted.max_api or some combination of them. "
if ! modinfo [ " mod " ] . has_all ( [ " name " , " version " , " authors " , " license " , " entrypoint " ] ) :
2023-08-25 14:34:57 +02:00
logger . error ( " CORE/cml.gd " , " The modinfo of modification located at " + config_loadpath + " / " + mod_name + " does not contain mod.name, mod.version, mod.authors, mod.license or mod.entrypoint or some combination of them. " )
2023-08-07 14:49:12 +02:00
return " The modinfo of modification located at " + config_loadpath + " / " + mod_name + " does not contain mod.name, mod.version, mod.authors, mod.license or mod.entrypoint or some combination of them. "
if not modinfo [ " wanted " ] [ " min_version " ] < = config_wanted_version or not modinfo [ " wanted " ] [ " max_version " ] > = config_wanted_version :
2023-08-25 14:34:57 +02:00
logger . error ( " CORE/cml.gd " , " The modification \" " + modinfo [ " mod " ] [ " name " ] + " does not match wanted version " + str ( config_wanted_version ) )
2023-08-07 14:49:12 +02:00
return " The modification \" " + modinfo [ " mod " ] [ " name " ] + " does not match wanted version " + str ( config_wanted_version )
if not modinfo [ " wanted " ] [ " min_api " ] < = config_wanted_api or not modinfo [ " wanted " ] [ " max_api " ] > = config_wanted_api :
2023-08-25 14:34:57 +02:00
logger . error ( " CORE/cml.gd " , " The modification \" " + modinfo [ " mod " ] [ " name " ] + " does not match wanted api " + str ( config_wanted_api ) )
2023-08-07 14:49:12 +02:00
return " The modification \" " + modinfo [ " mod " ] [ " name " ] + " does not match wanted api " + str ( config_wanted_api )
if ! FileAccess . file_exists ( config_loadpath + " / " + mod_name + " / " + modinfo [ " mod " ] [ " entrypoint " ] ) :
2023-08-25 14:34:57 +02:00
logger . error ( " CORE/cml.gd " , " The entrypoint for the modification \" " + modinfo [ " mod " ] [ " name " ] + " \" located at \" " + config_loadpath + " / " + mod_name + " / " + modinfo [ " mod " ] [ " entrypoint " ] + " \" does not exist " )
2023-08-07 14:49:12 +02:00
return " The entrypoint for the modification \" " + modinfo [ " mod " ] [ " name " ] + " \" located at \" " + config_loadpath + " / " + mod_name + " / " + modinfo [ " mod " ] [ " entrypoint " ] + " \" does not exist "
2023-08-25 14:34:57 +02:00
var entrypoint_script : Script = ResourceLoader . load ( config_loadpath + " / " + mod_name + " / " + modinfo [ " mod " ] [ " entrypoint " ] )
var entrypoint : Node = Node . new ( )
2023-08-07 14:49:12 +02:00
entrypoint . name = mod_name
entrypoint . set_script ( entrypoint_script )
get_tree ( ) . root . add_child ( entrypoint )
2023-08-25 14:34:57 +02:00
var mod_err : String = await get_node ( " /root/ " + mod_name ) . _start ( )
2023-08-07 14:49:12 +02:00
if mod_err == " " :
modlist . append ( mod_name )
return " "
else :
get_tree ( ) . root . remove_child ( entrypoint )
return " Modification \" " + mod_name + " \" could not be loaded as it returned this error: " + mod_err
func unload_mods ( ) - > void :
for mod in modlist :
await unload_mod ( mod )
func unload_mod ( mod_name : String ) - > void :
2023-08-25 14:34:57 +02:00
logger . info ( " CORE/cml.gd " , " Unloading modification \" " + mod_name + " \" " )
2023-08-07 14:49:12 +02:00
if ! modlist . has ( mod_name ) :
2023-08-25 14:34:57 +02:00
logger . error ( " CORE/cml.gd " , " Modification \" " + mod_name + " \" is not loaded " )
2023-08-07 14:49:12 +02:00
if get_tree ( ) . root . get_node_or_null ( mod_name ) == null :
2023-08-25 14:34:57 +02:00
core . exception ( " CORE/cml.gd " , " Could not locate mod entrypoint script for mod \" " + mod_name + " \" during unload " )
2023-08-07 14:49:12 +02:00
return
await get_node ( " /root/ " + mod_name ) . _stop ( )
get_tree ( ) . root . remove_child ( get_node ( " /root/ " + mod_name ) )
modlist . erase ( mod_name )
func register_hook ( mod_name : String , hook_name : String , hook_action : int , method : Callable ) - > bool :
if ! modlist . has ( mod_name ) :
2023-08-25 14:34:57 +02:00
core . exception ( " CORE/cml.gd " , " Failed registering hook \" " + hook_name + " \" for mod \" " + mod_name + " \" as it does not exist or is not loaded " )
2023-08-07 14:49:12 +02:00
return false
2023-08-25 14:34:57 +02:00
core . exception ( " CORE/cml.gd " , " Function not implemented " )
2023-08-07 14:49:12 +02:00
return true
func get_list ( ) - > Array :
return modlist
func get_info ( mod_name : String ) - > Dictionary :
if ! modlist . has ( mod_name ) :
return { " error " : " Modification \" " + mod_name + " \" is not loaded " }
2023-08-25 14:34:57 +02:00
var modinfo_raw : FileAccess = FileAccess . open ( config_loadpath + " / " + mod_name + " / " + config_wanted_name + " .coremod " , FileAccess . READ )
var modinfo : Dictionary = JSON . parse_string ( modinfo_raw . get_as_text ( ) )
2023-08-07 14:49:12 +02:00
modinfo_raw . close ( )
if modinfo == null :
2023-08-25 14:34:57 +02:00
return { " error " : " Failed parsing modinfo for modification \" " + mod_name + " \" " }
2023-08-07 14:49:12 +02:00
return modinfo
func load_configuration ( ) - > void :
if core . protection_mode : return
2023-08-25 14:34:57 +02:00
config_loadpath = core . config . cml_loadpath
config_wanted_name = core . config . cml_wanted_name
config_wanted_version = core . config . cml_wanted_version
if core . config . get ( " cml_wanted_api " ) == null :
2023-08-07 14:49:12 +02:00
config_wanted_api = config_wanted_version
else :
2023-08-25 14:34:57 +02:00
config_wanted_api = core . config . cml_wanted_api