CORE rewrite (#1)

Reviewed-on: StarOpenSource/core#1

Rewrote CORE and improved the startup process and startup time significantly. The documentation has been beefed up too and is now much better. Existing projects may need major refactoring however.
Co-authored-by: JeremyStarTM <jeremystartm@staropensource.de>
Co-committed-by: JeremyStarTM <jeremystartm@staropensource.de>
This commit is contained in:
JeremyStar™ 2023-08-25 14:34:57 +02:00 committed by JeremyStar™
parent ab5b3ade52
commit 99703cf03e
55 changed files with 2035 additions and 1985 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
*.import
config.gd
devprj

View file

@ -1,8 +1,9 @@
#!/bin/make
CORE=$(shell pwd)
ASSETS=$(CORE)/assets
DOCSCONF=$(CORE)/mkdocs.yml
DOCSOUT=$(CORE)/docs_out
TESTPROJECT=/tmp/core_devproject
TESTPROJECT=$(CORE)/devprj
dist: help
help:
@ -23,7 +24,6 @@ docs-deps-paru:
@paru -Sy --needed python-pyyaml-env-tag python-mergedeep python-six python-smmap python-gitdb python-urllib3 python-idna python-dateutil python-pytz python-babel python-requests python-regex python-pygments python-colorama python-watchdog python-packaging python-ghp-import python-click python-jinja python-yaml python-gitpython python-markupsafe pymdown-extensions mkdocs-material-pymdownx-extras mkdocs-git-revision-date-localized-plugin mkdocs-material mkdocs
docs-serve:
@echo ":: Serving documentation, press CTRL+C to exit"
# prevent make from terminating
@bash -c "mkdocs serve --dirtyreload --config-file "$(DOCSCONF)";exit 0"
docs-build:
@make docs-clean
@ -34,16 +34,12 @@ docs-clean:
@rm -rf "$(DOCSOUT)"
mkdevprj:
@echo ":: Creating development project"
@mkdir -p $(TESTPROJECT)/mods/testmod/
@echo -e "config_version=5\n[application]\nconfig/name=\"CORE development project\"\nrun/main_scene=\"res://CORE/coreinit.tscn\"\nconfig/use_custom_user_dir=true\nconfig/custom_user_dir_name=\"core_devproject\"\nconfig/features=PackedStringArray(\"4.1\", \"GL Compatibility\")\nboot_splash/bg_color=Color(0, 0, 0, 1)\nboot_splash/show_image=false\nconfig/icon=\"res://CORE/soscore.png\"\n[autoload]\nLogger=\"*res://CORE/logger.gd\"\nPreprocessor=\"*res://CORE/preprocessor.gd\"\n[display]\nwindow/size/viewport_width=960\nwindow/size/viewport_height=540\n[rendering]\nrenderer/rendering_method=\"gl_compatibility\"\nrenderer/rendering_method.mobile=\"gl_compatibility\"" > "$(TESTPROJECT)/project.godot"
@echo -e "extends Node\n\n@onready\nvar core: Node = get_node(\"/root/core\")\n\nfunc _ready() -> void:\n core.welcome()" > "$(TESTPROJECT)/init.gd"
@echo -e "extends Node\nvar core_startscript = \"res://init.gd\"\nvar wmgr_size_x = 960\nvar wmgr_size_y = 540\nvar wmgr_title = \"CORE development project\"\nvar wmgr_mode = 0\nvar splash_enabled = false\nvar splash_image = \"res://CORE/soscore.png\"\nvar splash_image_size = 256\nvar splash_color = \"000000\"\nvar moam_loadpath = \"res://mods/\"\nvar moam_wanted_name = \"coredevprj\"\nvar moam_wanted_version = 1\nvar moam_wanted_api = 1" > config.gd
@echo -e "{\n\"wanted\": {\n\"min_version\": 1,\n\"max_version\": 1,\n\"min_api\": 1,\n\"max_api\": 1\n},\n\"mod\": {\n\"name\": \"CORE Test Mod\",\n\"version\": 1,\n\"version_friendly\": "1.0",\n\"authors\": [\n\"The CORE Team\"\n],\n\"license\": \"GNU General Public License v3\",\n\"entrypoint\": \"testmod.gd\"\n}\n}" > "$(TESTPROJECT)/mods/testmod/coredevprj.coremod"
@echo -e "extends Node\n@onready\nvar core: Node = get_node(\"/root/core\")\nfunc _start() -> String:\n await get_tree().create_timer(0).timeout\n Logger.info(\"testmod\",\"_start() has been called.\")\n return \"\"\nfunc _stop() -> void:\n await get_tree().create_timer(0).timeout\n Logger.info(\"testmod\",\"_stop() has been called.\")" > "$(TESTPROJECT)/mods/testmod/testmod.gd"
@cp -r $(ASSETS)/testproject $(TESTPROJECT)
@ln -s $(CORE) $(TESTPROJECT)/CORE
@mv $(TESTPROJECT)/config.gd $(TESTPROJECT)/CORE/config.gd
@echo ":: Development project created."
@echo " You can now launch Godot and open '$(TESTPROJECT)'."
@echo " Don't forget to save and execute 'make rmdevprj' when you're finished."
@echo " If you want to submit your changes, remember to execute 'make rmdevprj' first!"
rmdevprj:
@echo ":: Removing development project"
@echo ":: !!!!!!!!!!!!!!!!!!!!!!!!!!!!"

View file

@ -11,15 +11,15 @@ CORE is under heavy development and can be very unstable. Please do not use CORE
- Notification API
- Basic debugging tool (CTRL+C to crash, F3 to toggle statistics)
- ~~Better documentation (docs4everything)~~
- Everything commented and explained
- ~~Everything commented and explained~~
- Documentation page explaining what does what (for CORE noobies)
- ~~Autoload singleton check removal~~
- More wmgr functions
- ~~More wmgr functions~~ (the window manager got removed in the rewrite)
- ~~Website~~
- ~~Silencing startup messages (info -> diag)~~
- ~~Remove autoload component~~
- ~~Fix syntax (set return types missing)~~
- Much more configuration options
- ~~Much more configuration options~~ (CORE's already pretty configurable)
- Implement preprocessor placeholders
- Clipboard content
- CORE version
@ -69,13 +69,12 @@ CORE is under heavy development and can be very unstable. Please do not use CORE
Yes, in theory you can refactor your entire codebase and make a giant mess, but we don't recommend doing that.
# Requirements
- Godot 4.0/4.1 (stable releases only)
- Godot 4.1 (stable releases only)
- Good experience with Godot 4 and GDScript
# Recommendations
- Use smgr instead of manually managing scenes or CORE will break apart. If you don't want headaches, use smgr.
- Use the CORE logger for logging. It supports rich formatting (using tags, handled by our Preprocessor™) and is generally better than using print() for everything.
- Use wmgr for managing the main window title, size, position, etc.
- Use the Scene Manager instead of manually managing scenes or CORE will break apart. If you don't want headaches, use the Scene Manager.
- Use the CORE's logger implementation instead of print(). It supports rich formatting (using tags, handled by our Preprocessor™) and is generally better than using print() for everything.
# How to install
- Download the [CORE manager](https://git.staropensource.de/StarOpenSource/core-manager#download) and open it

View file

@ -0,0 +1,9 @@
extends Node
@onready
var core: Node = get_node("/root/CORE")
@onready
var logger: Node = core.get_module("Logger")
func _ready() -> void:
logger.info("init.gd","init.gd loaded.")

View file

@ -0,0 +1,18 @@
{
"wanted": {
"min_version": 1,
"max_version": 1,
"min_api": 1,
"max_api": 1
},
"mod": {
"name": "CORE Test Mod",
"version": 1,
"version_friendly": 1.0,
"authors": [
"The CORE Team"
],
"license": "GNU General Public License v3",
"entrypoint": "testmod.gd"
}
}

View file

@ -0,0 +1,15 @@
extends Node
@onready
var core: Node = get_node("/root/core")
@onready
var logger: Node = core.get_module("Logger")
func _start() -> String:
await get_tree().create_timer(0).timeout
logger.info("testmod","_start() has been called.")
return ""
func _stop() -> void:
await get_tree().create_timer(0).timeout
logger.info("testmod","_stop() has been called.")

View file

@ -0,0 +1,29 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="CORE development project"
run/main_scene="res://CORE/coreinit.tscn"
config/use_custom_user_dir=true
config/custom_user_dir_name="core_devproject"
config/features=PackedStringArray("4.1", "GL Compatibility")
boot_splash/bg_color=Color(0, 0, 0, 1)
boot_splash/show_image=false
[display]
window/size/viewport_width=960
window/size/viewport_height=540
[rendering]
renderer/rendering_method="gl_compatibility"
renderer/rendering_method.mobile="gl_compatibility"

View file

@ -1,38 +0,0 @@
[gd_scene load_steps=3 format=3]
[ext_resource type="FontFile" path="res://CORE/hack.ttf" id="1_lr4q1"]
[ext_resource type="Script" path="res://CORE/corelog.gd" id="2_6qdog"]
[node name="COREBackground" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Background" type="ColorRect" parent="."]
layout_mode = 0
offset_right = 960.0
offset_bottom = 540.0
color = Color(0, 0, 0, 1)
[node name="Log" type="RichTextLabel" parent="Background"]
layout_mode = 0
offset_right = 960.0
offset_bottom = 540.0
theme_override_colors/default_color = Color(1, 1, 1, 1)
theme_override_fonts/normal_font = ExtResource("1_lr4q1")
theme_override_fonts/bold_font = ExtResource("1_lr4q1")
theme_override_fonts/italics_font = ExtResource("1_lr4q1")
theme_override_fonts/bold_italics_font = ExtResource("1_lr4q1")
theme_override_fonts/mono_font = ExtResource("1_lr4q1")
theme_override_font_sizes/normal_font_size = 12
theme_override_font_sizes/bold_font_size = 12
theme_override_font_sizes/italics_font_size = 12
theme_override_font_sizes/bold_italics_font_size = 12
theme_override_font_sizes/mono_font_size = 12
bbcode_enabled = true
text = "(coreinit) [INFO] Initializing CORE"
scroll_following = true
script = ExtResource("2_6qdog")

View file

@ -1,70 +1,78 @@
# moam.gd
# Mother Of All Mods (the CORE modloader)
#
# This file is part of StarOpenSource CORE (SOSCORE)
# Made by the StarOpenSource Project and Contributers
# Licensed under GNU GPLv3
######################################
# 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) #
######################################
extends Node
@onready
var core = get_node("/root/core")
# CORE modules
var core: Node = null
var logger: Node = null
# Configuration
var config_loadpath = null
var config_wanted_name = null
var config_wanted_version = null
var config_wanted_api = null
# Modification list
var modlist = []
# Hook list
var hooks = {}
func load_mods() -> Array:
if core.protection_mode: return []
var errors = []
var errors: Array = []
for directory in DirAccess.get_directories_at(config_loadpath):
var return_value = await load_mod(directory)
var return_value: String = await load_mod(directory)
if return_value != "":
errors.append(return_value)
return errors
func load_mod(mod_name:String) -> String:
Logger.info("moam","Loading modification \"" + mod_name + "\"")
logger.info("CORE/cml.gd","Loading modification \"" + mod_name + "\"")
if modlist.has(mod_name):
Logger.error("moam","Modification \"" + mod_name + "\" is already loaded")
logger.error("CORE/cml.gd","Modification \"" + mod_name + "\" is already loaded")
if !FileAccess.file_exists(config_loadpath + "/" + mod_name + "/" + config_wanted_name + ".coremod"):
Logger.error("moam","Modification located at " + config_loadpath + "/" + mod_name + " does not contain a " + config_wanted_name + ".coremod file")
logger.error("CORE/cml.gd","Modification located at " + config_loadpath + "/" + mod_name + " does not contain a " + config_wanted_name + ".coremod file")
return "Modification located at " + config_loadpath + "/" + mod_name + " does not contain a " + config_wanted_name + ".coremod file"
var modinfo_raw = FileAccess.open(config_loadpath + "/" + mod_name + "/" + config_wanted_name + ".coremod",FileAccess.READ)
var modinfo = modinfo_raw.get_as_text()
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())
modinfo_raw.close()
modinfo = JSON.parse_string(modinfo)
if modinfo == null:
Logger.error("moam","Failed modinfo parsing for modification located at " + config_loadpath + "/" + mod_name)
logger.error("CORE/cml.gd","Failed modinfo parsing for modification located at " + config_loadpath + "/" + mod_name)
return "Failed modinfo parsing for modification located at " + config_loadpath + "/" + mod_name
if !modinfo.has_all(["wanted","mod"]):
Logger.error("moam","The modinfo of modification located at " + config_loadpath + "/" + mod_name + " does not contain wanted, mod or both")
logger.error("CORE/cml.gd","The modinfo of modification located at " + config_loadpath + "/" + mod_name + " does not contain wanted, mod or both")
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"]):
Logger.error("moam","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.")
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.")
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"]):
Logger.error("moam","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.")
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.")
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:
Logger.error("moam","The modification \"" + modinfo["mod"]["name"] + " does not match wanted version " + str(config_wanted_version))
logger.error("CORE/cml.gd","The modification \"" + modinfo["mod"]["name"] + " does not match wanted version " + str(config_wanted_version))
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:
Logger.error("moam","The modification \"" + modinfo["mod"]["name"] + " does not match wanted api " + str(config_wanted_api))
logger.error("CORE/cml.gd","The modification \"" + modinfo["mod"]["name"] + " does not match wanted api " + str(config_wanted_api))
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"]):
Logger.error("moam","The entrypoint for the modification \"" + modinfo["mod"]["name"] + "\" located at \"" + config_loadpath + "/" + mod_name + "/" + modinfo["mod"]["entrypoint"] + "\" does not exist")
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")
return "The entrypoint for the modification \"" + modinfo["mod"]["name"] + "\" located at \"" + config_loadpath + "/" + mod_name + "/" + modinfo["mod"]["entrypoint"] + "\" does not exist"
var entrypoint_script = ResourceLoader.load(config_loadpath + "/" + mod_name + "/" + modinfo["mod"]["entrypoint"])
var entrypoint = Control.new()
var entrypoint_script: Script = ResourceLoader.load(config_loadpath + "/" + mod_name + "/" + modinfo["mod"]["entrypoint"])
var entrypoint: Node = Node.new()
entrypoint.name = mod_name
entrypoint.set_script(entrypoint_script)
get_tree().root.add_child(entrypoint)
var mod_err = await get_node("/root/" + mod_name)._start()
var mod_err: String = await get_node("/root/" + mod_name)._start()
if mod_err == "":
modlist.append(mod_name)
return ""
@ -77,11 +85,11 @@ func unload_mods() -> void:
await unload_mod(mod)
func unload_mod(mod_name:String) -> void:
Logger.info("moam","Unloading modification \"" + mod_name + "\"")
logger.info("CORE/cml.gd","Unloading modification \"" + mod_name + "\"")
if !modlist.has(mod_name):
Logger.error("moam","Modification \"" + mod_name + "\" is not loaded")
logger.error("CORE/cml.gd","Modification \"" + mod_name + "\" is not loaded")
if get_tree().root.get_node_or_null(mod_name) == null:
core.exception("moam","Could not locate mod entrypoint script for mod \"" + mod_name + "\" during unload")
core.exception("CORE/cml.gd","Could not locate mod entrypoint script for mod \"" + mod_name + "\" during unload")
return
await get_node("/root/" + mod_name)._stop()
get_tree().root.remove_child(get_node("/root/" + mod_name))
@ -89,10 +97,9 @@ func unload_mod(mod_name:String) -> void:
func register_hook(mod_name:String,hook_name:String,hook_action:int,method:Callable) -> bool:
if !modlist.has(mod_name):
core.exception("moam","Failed registering hook \"" + hook_name + "\" for mod \"" + mod_name + "\" as it does not exist or is not loaded")
core.exception("CORE/cml.gd","Failed registering hook \"" + hook_name + "\" for mod \"" + mod_name + "\" as it does not exist or is not loaded")
return false
if hooks.has(hook_name):
Logger.error("moam","Failed registering hook \"" + hook_name + "\" for mod \"" + mod_Name + "\" as the hook already exists")
core.exception("CORE/cml.gd","Function not implemented")
return true
func get_list() -> Array:
@ -101,23 +108,19 @@ func get_list() -> Array:
func get_info(mod_name:String) -> Dictionary:
if !modlist.has(mod_name):
return {"error":"Modification \"" + mod_name + "\" is not loaded"}
var modinfo_raw = FileAccess.open(config_loadpath + "/" + mod_name + "/" + config_wanted_name + ".coremod",FileAccess.READ)
var modinfo = JSON.parse_string(modinfo_raw.get_as_text())
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())
modinfo_raw.close()
if modinfo == null:
return {"error":"Failed parsing modinfo for modification \"" + modinfo + "\""}
return {"error":"Failed parsing modinfo for modification \"" + mod_name + "\""}
return modinfo
func load_configuration() -> void:
if core.protection_mode: return
config_loadpath = core.config.moam_loadpath
config_wanted_name = core.config.moam_wanted_name
config_wanted_version = core.config.moam_wanted_version
if core.config.get("moam_wanted_api") == null:
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:
config_wanted_api = config_wanted_version
else:
config_wanted_api = core.config.moam_wanted_api
func initialize() -> void:
if core.protection_mode: return
core.setready()
config_wanted_api = core.config.cml_wanted_api

242
core.gd
View file

@ -1,90 +1,120 @@
# core.gd
# CORE Holder
#
# This file is part of StarOpenSource CORE (SOSCORE)
# Made by the StarOpenSource Project and Contributers
# Licensed under GNU GPLv3
######################################
# 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) #
######################################
extends Node
const version = "source 0"
var protection_mode = false
var locked = false
var readycount = 0
var readylized = false # Fun Fact: "ready" is a signal from "Node" and I (JeremyStarTM) just added "lized" from "initialized" to it to avoid a error thrown by Godot
var config = null
var wmgr = null
var smgr = null
var resmgr = null
var events = null
var splash = null
var moam = null
var mkdown = null
enum Errors {UNKNOWN}
enum Responsibilities {UNKNOWN}
# CORE modules
var logger: Node = null
var preprocessor: Node = null
var config: Node = null
func attach(type:String,module,do_setup:bool = true) -> void:
if protection_mode: return
if locked:
return
Logger.diag("core","Attaching " + type + " to CORE")
var mod = module
if do_setup:
mod = Control.new()
mod.name = type
mod.set_script(module)
match(type):
"config": config = mod
"wmgr": wmgr = mod
"smgr": smgr = mod
"resmgr": resmgr = mod
"events": events = mod
"splash": splash = mod
"moam": moam = mod
"mkdown": mkdown = mod
_:
exception("core","Attaching \"" + type + "\" failed as it is not a valid module")
mod.free()
return
add_child(mod)
Logger.diag("core","Attached " + type + " successfully")
# Version
const version: Dictionary = {"type":"source","releasebuild":0,"full":"source 0"}
# Protection mode
var protection_mode: bool = false
# Development mode
var development_mode: bool = false
# Loadpath (from coreinit.gd)
var loadpath: String = ""
func setready() -> void:
if protection_mode: return
readycount = readycount+1
if readycount == 7:
readylized = true
func lock() -> void:
if protection_mode: return
locked = true
Logger.diag("core","CORE is now locked. No new attachments can be added.")
# Errors
enum Errors {
OK,
CORE_PROTECTIONMODE,
CORE_EXCEPTION,
CORE_INVALID_MODULE,
RESOURCEMANAGER_ALREADY_EXISTS,
RESOURCEMANAGER_INVALID_FILEPATH,
RESOURCEMANAGER_RESOURCE_MISSING,
RESOURCEMANAGER_BATCH_EMPTY,
SCENEMANAGER_ALREADY_LOADED,
SCENEMANAGER_NOT_LOADED,
SCENEMANAGER_NOT_PACKEDSCENE
}
func welcome() -> void:
if protection_mode: return
Logger.info("core","CORE (" + version + ") welcomes you!<nl>It seems like everything is working :)")
logger.info("CORE/core.gd","CORE (" + version["full"] + ") welcomes you!<nl>It seems like everything is working :)")
func exception(script:String,error:String):
func reload_config() -> void:
var corelog: Node = get_node("/root/CORE/CORELog")
var debugdisplay: Node = get_node("/root/CORE/DebugDisplay")
var resourcemanager: Node = get_node("/root/CORE/ResourceManager")
var splash: Node = get_node("/root/CORE/SplashScreen")
preprocessor.enabled = get_config("preprocessor_enabled",true)
preprocessor.diagnostic = get_config("preprocessor_diagnostic",false)
logger.enabled = get_config("logger_enabled",true)
logger.diagnostic = get_config("logger_diagnostic",false)
if get_config("corelog_enabled",true):
corelog.display()
else:
corelog.dissolve()
debugdisplay.config_enabled = get_config("debugdisplay_enabled",true)
debugdisplay.config_fps = get_config("debugdisplay_fps",true)
debugdisplay.config_delta = get_config("debugdisplay_delta",true)
debugdisplay.config_rendertime = get_config("debugdisplay_rendertime",true)
debugdisplay.config_memory = get_config("debugdisplay_memory",true)
resourcemanager.config_load_invalid_file_as_null = get_config("resourcemanager_load_invalid_file_as_null",false)
splash.config_enabled = get_config("splash_enabled",false)
splash.config_image = get_config("splash_image","[LOADPATH]soscore.png").replace("[LOADPATH]",loadpath)
splash.config_image_size = get_config("config.splash_image_size",256)
splash.config_color = get_config("config.splash_color","#d60532")
splash.apply_config()
func get_config(config_key:StringName,default_value:Variant) -> Variant:
if protection_mode: return null
if config.get(config_key) == null:
return default_value
else:
return config.get(config_key)
func get_module(module_name:String) -> Node:
if protection_mode: return null
if module_name == "CORELog":
var err = error("CORE",Errors.CORE_INVALID_MODULE,{"module":module_name})
logger.error("CORE/core.gd",err["error"])
return err["code"]
var module: Node = get_node_or_null("/root/CORE/" + module_name)
if module == null:
var err = error("CORE",Errors.CORE_INVALID_MODULE,{"module":module_name})
logger.error("CORE/core.gd",err["error"])
return err["code"]
return module
func devmode():
logger.warn("CORE/core.gd","Development mode is now active.<nl>Keep this disabled if you don't know what you're doing<nl>or you may encounter serious issues!<nl><nl>You have been warned!")
logger.warn("CORE/core.gd","The development mode does nothing as of now. It is just \"a thing\" implemented for the future")
development_mode = true
func exception(module:String,exception_error:String):
protection_mode = true
var exc_message = """
var submit_issue_default = "Please report this crash to the CORE Framework repository (with
the full log file). You can submit a crash report at:
https://git.staropensource.de/StarOpenSource/core/issues/new"
var submit_issue_devmode = """Please do NOT report this crash to the CORE Framework repository
as CORE is running in development mode, which is not supported."""
var exc_message: String = """
[color=red]################################
EXCEPTION! EXCEPTION! EXCEPTION!
The CORE Framework experienced a critical error in runtime.
Please report this crash to the CORE Framework repository (with
the full log file). You can submit a crash report at:
https://git.staropensource.de/StarOpenSource/core/issues/new
%submit_issue%
CORE INFORMATION
version = "%version%"
readylized = %readylized%
readycount = %readycount%
locked = %locked%
development_mode = %development_mode%
preprocessor_enabled = %preprocessor_enabled%
preprocessor_tests = %preprocessor_tests%
preprocessor_tests_executed = %preprocessor_tests_executed%
preprocessor_tests_success = %preprocessor_tests_success%
preprocessor_diagnostic = %preprocessor_diagnostic%
logger_enabled = %logger_enabled%
logger_diag = %logger_diag%
logger_diagnostic = %logger_diagnostic%
OPERATING SYSTEM
timezone = %timezone%
@ -110,7 +140,7 @@ permissions = %permissions%
debug_build = %debug_build%
ERROR INFORMATION
script = "%script%"
module = "%module%"
error = "%error%"
STACKTRACE
@ -119,17 +149,16 @@ STACKTRACE
EXCEPTION! EXCEPTION! EXCEPTION!
################################
"""
exc_message = exc_message.replace("%version%",version)
exc_message = exc_message.replace("%readylized%",str(readylized))
exc_message = exc_message.replace("%readycount%",str(readycount))
exc_message = exc_message.replace("%locked%",str(locked))
exc_message = exc_message.replace("%preprocessor_enabled%",str(Preprocessor.enabled))
exc_message = exc_message.replace("%preprocessor_tests%",str(Preprocessor.tests_enabled))
exc_message = exc_message.replace("%preprocessor_tests_executed%",str(Preprocessor.tests_executed))
exc_message = exc_message.replace("%preprocessor_tests_success%",str(Preprocessor.tests_success))
exc_message = exc_message.replace("%logger_enabled%",str(Logger.enable))
exc_message = exc_message.replace("%logger_diag%",str(Logger.enable_diag))
if development_mode:
exc_message = exc_message.replace("%submit_issue%",submit_issue_devmode)
else:
exc_message = exc_message.replace("%submit_issue%",submit_issue_default)
exc_message = exc_message.replace("%version%",version["full"])
exc_message = exc_message.replace("%development_mode%",str(development_mode))
exc_message = exc_message.replace("%preprocessor_enabled%",str(preprocessor.enabled))
exc_message = exc_message.replace("%preprocessor_diagnostic%",str(preprocessor.diagnostic))
exc_message = exc_message.replace("%logger_enabled%",str(logger.enabled))
exc_message = exc_message.replace("%logger_diagnostic%",str(logger.diagnostic))
exc_message = exc_message.replace("%timezone%",str(Time.get_time_zone_from_system()))
exc_message = exc_message.replace("%time_utc%",Time.get_time_string_from_system(true))
@ -152,22 +181,51 @@ EXCEPTION! EXCEPTION! EXCEPTION!
exc_message = exc_message.replace("%permissions%",str(OS.get_granted_permissions()))
exc_message = exc_message.replace("%debug_build%",str(OS.is_debug_build()))
exc_message = exc_message.replace("%script%",script)
exc_message = exc_message.replace("%error%",error)
exc_message = exc_message.replace("%module%",module)
exc_message = exc_message.replace("%error%",exception_error)
exc_message = exc_message.replace("%stacktrace%",str(get_stack()))
print_rich(exc_message)
await get_tree().create_timer(0.25).timeout
get_tree().quit(255)
func error(module:String,respo:Responsibilities,error:Errors,error_info:Dictionary = {}) -> Dictionary:
var error_text = ""
match(respo):
Responsibilities["UNKNOWN"]:
pass
match(error):
Errors["UNKNOWN"]:
error_text = ""
func error(module:String,error_enum:Errors,error_info:Dictionary = {}) -> Dictionary:
match(error_enum):
Errors.OK:
exception("core","Module \"" + module + "\" tried recieving information about error OK (are you ok?)")
Errors.CORE_PROTECTIONMODE:
return {"code":9223372036854775807,"error":"CORE is in protection mode and is unavailable"}
Errors.CORE_EXCEPTION:
return {"code":9223372036854775806,"error":"Launching nuke in 3... 2... 1..."}
Errors.CORE_INVALID_MODULE:
return {"code":Errors.CORE_INVALID_MODULE,"error":"The CORE module \"" + error_info["module"] + "\" does not exist"}
Errors.RESOURCEMANAGER_ALREADY_EXISTS:
return {"code":Errors.RESOURCEMANAGER_ALREADY_EXISTS,"error":"Failed loading resource: The resource \"" + error_info["name"] + "\" is already loaded"}
Errors.RESOURCEMANAGER_INVALID_FILEPATH:
return {"code":Errors.RESOURCEMANAGER_INVALID_FILEPATH,"error":"Failed loading resource: The filepath \"" + error_info["filepath"] + "\" is invalid"}
Errors.RESOURCEMANAGER_RESOURCE_MISSING:
return {"code":Errors.RESOURCEMANAGER_RESOURCE_MISSING,"error":"Failed unloading resource: The resource \"" + error_info["name"] + "\" is not loaded"}
Errors.RESOURCEMANAGER_BATCH_EMPTY:
return {"code":Errors.RESOURCEMANAGER_BATCH_EMPTY,"error":"Failed processing batch: The batch is empty"}
Errors.SCENEMANAGER_ALREADY_LOADED:
if error_info["one_scene_overlay"]:
return {"code":Errors.SCENEMANAGER_ALREADY_LOADED,"error":"Failed adding scene \"" + error_info["scene"] + "\" to overlay \"" + error_info["overlay"] + "\": The overlay is full"}
else:
return {"code":Errors.SCENEMANAGER_ALREADY_LOADED,"error":"Failed adding scene \"" + error_info["scene"] + "\" to overlay \"" + error_info["overlay"] + "\": A resource with the same name is already present in that overlay"}
Errors.SCENEMANAGER_NOT_LOADED:
if error_info["one_scene_overlay"]:
return {"code":Errors.SCENEMANAGER_ALREADY_LOADED,"error":"Failed removing scene \"" + error_info["scene"] + "\" from overlay \"" + error_info["overlay"] + "\": The overlay is empty"}
else:
return {"code":Errors.SCENEMANAGER_ALREADY_LOADED,"error":"Failed removing scene \"" + error_info["scene"] + "\" from overlay \"" + error_info["overlay"] + "\": A resource with that name could not be found within the overlay"}
Errors.SCENEMANAGER_NOT_PACKEDSCENE:
return {"code":Errors.SCENEMANAGER_NOT_PACKEDSCENE,"error":"Failed adding scene \"" + error_info["scene"] + "\" to overlay \"" + error_info["overlay"] + "\": The specified resource is not a PackedScene"}
_:
exception("core","Failed generating error: Invalid error \"" + str(error) + "\"")
return {}
return error("CORE",Errors.CORE_EXCEPTION)
func exit_safely(exitcode:int = 0) -> void:
if protection_mode: return
logger.info("CORE/core.gd","Shutting down...")
protection_mode = true
await get_tree().create_timer(0.5).timeout
get_tree().quit(exitcode)

View file

@ -1,51 +1,209 @@
# coreinit.gd
# CORE Initializer
#
# This file is part of StarOpenSource CORE (SOSCORE)
# Made by the StarOpenSource Project and Contributers
# Licensed under GNU GPLv3
######################################
# 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) #
######################################
extends Node
@onready
var engine_version = Engine.get_version_info()
var loadpath: String = "res://CORE/"
# To workaround the "busy setting up children" issue coreinit.gd
# "reloads" itself. I don't know why it works, but it works.
func _ready() -> void:
if name == "COREINIT":
initialize()
else:
print("coreinit -> \"Fixing\" busy setting up children issue")
var coreinit_raw: Script = ResourceLoader.load(loadpath + "coreinit.gd")
var coreinit: Node = Node.new()
coreinit.name = "COREINIT"
coreinit.set_script(coreinit_raw)
get_tree().root.add_child.call_deferred(coreinit)
if loadpath == "":
coreinit.set_deferred("loathpath","res://CORE/")
else:
coreinit.set_deferred("loadpath",loadpath)
queue_free()
# Bootstraps CORE
func initialize() -> void:
print("coreinit -> Bootstrapping CORE")
# Check requirements and quit if not met
if !check_requirements():
await get_tree().create_timer(0.25).timeout
get_tree().quit(255)
return
# Load module scripts and scenes
print("coreinit -> Loading modules")
var mod_config_raw: Script = ResourceLoader.load(loadpath + "config.gd")
var mod_corelog_raw: PackedScene = ResourceLoader.load(loadpath + "corelog.tscn")
var mod_logger_raw: Script = ResourceLoader.load(loadpath + "logger.gd")
var mod_preprocessor_raw: Script = ResourceLoader.load(loadpath + "preprocessor.gd")
var mod_core_raw: Script = ResourceLoader.load(loadpath + "core.gd")
var mod_misc_raw: Script = ResourceLoader.load(loadpath + "misc.gd")
var mod_debugdisplay_raw: PackedScene = ResourceLoader.load(loadpath + "debugdisplay.tscn")
var mod_splash_raw: PackedScene = ResourceLoader.load(loadpath + "splash.tscn")
var mod_resmgr_raw: Script = ResourceLoader.load(loadpath + "resmgr.gd")
var mod_smgr_raw: Script = ResourceLoader.load(loadpath + "smgr.gd")
var mod_events_raw: Script = ResourceLoader.load(loadpath + "events.gd")
#var mod_cml_raw: Script = ResourceLoader.load(loadpath + "cml.gd")
var mod_mkdown_raw: Script = ResourceLoader.load(loadpath + "mkdown.gd")
# Create nodes and add the raw scripts + give them names
print("coreinit -> Constructing modules")
var mod_config: Node = Node.new()
mod_config.name = "Config"
mod_config.set_script(mod_config_raw)
var mod_preprocessor: Node = Node.new()
mod_preprocessor.name = "Preprocessor"
mod_preprocessor.set_script(mod_preprocessor_raw)
var mod_logger: Node = Node.new()
mod_logger.name = "Logger"
mod_logger.set_script(mod_logger_raw)
var mod_corelog: Node = mod_corelog_raw.instantiate()
mod_corelog.name = "CORELog"
var mod_core: Node = Node.new()
mod_core.name = "CORE"
mod_core.set_script(mod_core_raw)
mod_core.loadpath = loadpath
var mod_misc: Node = Node.new()
mod_misc.name = "Miscellaneous"
mod_misc.set_script(mod_misc_raw)
var mod_debugdisplay: Node = mod_debugdisplay_raw.instantiate()
mod_debugdisplay.name = "DebugDisplay"
var mod_splash: Node = mod_splash_raw.instantiate()
mod_splash.name = "SplashScreen"
var mod_resmgr: Node = Node.new()
mod_resmgr.name = "ResourceManager"
mod_resmgr.set_script(mod_resmgr_raw)
var mod_smgr: Node = Node.new()
mod_smgr.name = "SceneManager"
mod_smgr.set_script(mod_smgr_raw)
var mod_events: Node = Node.new()
mod_events.name = "Events"
mod_events.set_script(mod_events_raw)
#var mod_cml: Node = Node.new()
#mod_cml.name = "ModLoader"
#mod_cml.set_script(mod_cml_raw)
var mod_mkdown: Node = Node.new()
mod_mkdown.name = "Markdown"
mod_mkdown.set_script(mod_mkdown_raw)
# Add all modules to /root/
print("coreinit -> Injecting modules")
get_tree().root.add_child(mod_core)
mod_core.add_child(mod_config)
mod_core.add_child(mod_preprocessor)
mod_core.add_child(mod_logger)
mod_core.add_child(mod_misc)
mod_core.add_child(mod_corelog)
mod_core.add_child(mod_debugdisplay)
mod_core.add_child(mod_splash)
mod_core.add_child(mod_resmgr)
mod_core.add_child(mod_smgr)
#mod_core.add_child(mod_cml)
mod_core.add_child(mod_events)
mod_core.add_child(mod_mkdown)
# Updates references to other modules
print("coreinit -> Updating dependency references")
mod_corelog.core = mod_core
mod_corelog.logger = mod_logger
mod_preprocessor.core = mod_core
mod_preprocessor.logger = mod_logger
mod_logger.core = mod_core
mod_logger.preprocessor = mod_preprocessor
mod_core.logger = mod_logger
mod_core.preprocessor = mod_preprocessor
mod_core.config = mod_config
mod_misc.core = mod_core
mod_debugdisplay.core = mod_core
mod_debugdisplay.misc = mod_misc
mod_splash.core = mod_core
mod_splash.logger = mod_logger
mod_resmgr.core = mod_core
mod_resmgr.logger = mod_logger
mod_smgr.logger = mod_logger
mod_smgr.core = mod_core
mod_smgr.resourcemanager = mod_resmgr
mod_events.core = mod_core
#mod_cml.core = mod_core
#mod_cml.logger = mod_logger
mod_events.logger = mod_logger
mod_mkdown.core = mod_core
mod_mkdown.logger = mod_logger
# Apply config to base modules
print("coreinit -> Applying configuration to base modules")
mod_preprocessor.enabled = get_config(mod_config,"preprocessor_enabled",true)
mod_preprocessor.diagnostic = get_config(mod_config,"preprocessor_diagnostic",false)
mod_logger.enabled = get_config(mod_config,"logger_enabled",true)
mod_logger.diagnostic = get_config(mod_config,"logger_diagnostic",false)
if get_config(mod_config,"corelog_enable",true):
mod_corelog.display()
else:
mod_corelog.dissolve()
# Call initialize() on base modules
print("coreinit -> Initializing base modules")
mod_corelog.initialize()
mod_logger.initialize()
mod_preprocessor.initialize()
# Apply config to all modules
mod_logger.diag("CORE/coreinit.gd","Reloading configuration")
mod_core.reload_config()
# Call initialize() method on all modules
mod_logger.diag("CORE/coreinit.gd","Initializing modules")
#mod_splash.initialize() ## Has no initialize() method
#mod_resmgr.initialize() ## Has no initialize() method
mod_smgr.initialize()
#mod_cml.initialize()
mod_events.initialize()
# Inject init script
mod_logger.diag("CORE/coreinit.gd","Loading init script")
if !FileAccess.file_exists(get_config(mod_config,"startup_script","res://init.gd")):
mod_core.exception("CORE/coreinit.gd","Startup script located at \"" + get_config(mod_config,"startup_script","res://init.gd") + "\" does not exist")
return
var initscr_raw: Script = ResourceLoader.load(get_config(mod_config,"core_initscript","res://init.gd"))
mod_logger.diag("CORE/coreinit.gd","Constructing init script")
var initscr: Node = Node.new()
initscr.name = "InitializationScript"
initscr.set_script(initscr_raw)
mod_logger.diag("CORE/coreinit.gd","Injecting init script")
get_tree().root.add_child(initscr)
mod_logger.diag("CORE/coreinit.gd","Bootstrapped CORE, exiting.")
queue_free()
# Retrieves a key's value from the configuration file
func get_config(config:Node,config_key:StringName,default_value:Variant) -> Variant:
if config.get(config_key) == null:
return default_value
else:
return config.get(config_key)
# Check CORE's requirements
func check_requirements() -> bool:
var engine_version: Dictionary = Engine.get_version_info()
print("coreinit -> Checking CORE requirements")
# Check if Godot major version is exactly 4
if engine_version["major"] != 4:
print("coreinit -> CORE only supports Godot 4. Please upgrade/downgrade your Godot Project to Godot 4.")
await get_tree().create_timer(0.1).timeout
get_tree().quit(141)
return
if engine_version["minor"] != 0 and engine_version["minor"] != 1:
print("coreinit -> CORE only supports Godot 4.0 and 4.1. Please upgrade/downgrade your Godot Project to Godot 4.0 or 4.1.")
await get_tree().create_timer(0.1).timeout
get_tree().quit(142)
return
print("coreinit -> Error: CORE only supports Godot 4.1.stable releases.")
return false
# Check if Godot minor version is exactly 1
if engine_version["minor"] != 1:
print("coreinit -> Error: CORE only supports Godot 4.1.stable releases.")
return false
# Check if Godot release channel is "stable"
if engine_version["status"] != "stable":
print("coreinit -> CORE only supports stable Godot 4 releases. Please upgrade/downgrade your Godot Project to a stable version.")
await get_tree().create_timer(0.1).timeout
get_tree().quit(143)
return
if get_node_or_null(NodePath("/root/Logger")) == null:
print("coreinit -> The CORE logger is missing in your autoload project settings!")
await get_tree().create_timer(0.1).timeout
get_tree().quit(144)
return
if get_node_or_null(NodePath("/root/Preprocessor")) == null:
print("coreinit -> The CORE preprocessor is missing in your autoload project settings!")
await get_tree().create_timer(0.1).timeout
get_tree().quit(145)
return
if !FileAccess.file_exists("res://CORE/config.gd"):
print("coreinit -> The CORE configuration file (config.gd) is missing! Please copy the config.gd.example file and rename it to config.gd!")
await get_tree().create_timer(0.1).timeout
get_tree().quit(146)
return
print("coreinit -> Constructing coreloader")
var coreloader = Control.new()
coreloader.name = "coreloader"
coreloader.set_script(ResourceLoader.load("res://CORE/coreloader.gd"))
print("coreinit -> Injecting coreloader")
get_tree().root.add_child.call_deferred(coreloader)
print("coreinit -> Switching to COREBackground")
get_tree().change_scene_to_packed(ResourceLoader.load("res://CORE/background.tscn"))
print("coreinit -> Error: CORE only supports Godot 4.1.stable releases.")
return false
# Display warning if autoloads are used
if get_tree().root.get_child_count(true) != 2:
print("coreinit -> Warning: We do not recommend using autoloads in your project as bugs may occur.")
# Check if configuration file exists
if !FileAccess.file_exists(loadpath + "config.gd"):
print("coreinit -> Error: The CORE configuration file is missing. Use CORE Manager to repair your project.")
return false
# Success!
return true

View file

@ -2,13 +2,10 @@
[ext_resource type="Script" path="res://CORE/coreinit.gd" id="1_ubktt"]
[node name="coreinit" type="Control"]
layout_mode = 3
anchors_preset = 0
[node name="coreinit" type="Node"]
script = ExtResource("1_ubktt")
[node name="ColorRect" type="ColorRect" parent="."]
layout_mode = 0
offset_left = -5e+08
offset_top = -5e+08
offset_right = 5e+08

View file

@ -1,66 +0,0 @@
# coreloader.gd
# CORE Loader
#
# This file is part of StarOpenSource CORE (SOSCORE)
# Made by the StarOpenSource Project and Contributers
# Licensed under GNU GPLv3
extends Node
func _ready() -> void:
await get_tree().create_timer(1.5).timeout
Logger.diag("coreloader","Starting initialization")
Logger.diag("coreloader","Loading configuration file")
var scr_config = ResourceLoader.load("res://CORE/config.gd")
Logger.diag("coreloader","Preloading core scripts")
var scr_core = ResourceLoader.load("res://CORE/core.gd")
var scr_wmgr = ResourceLoader.load("res://CORE/wmgr.gd")
var scr_smgr = ResourceLoader.load("res://CORE/smgr.gd")
var scr_resmgr = ResourceLoader.load("res://CORE/resmgr.gd")
var scr_events = ResourceLoader.load("res://CORE/events.gd")
var scr_splash = ResourceLoader.load("res://CORE/splash.tscn").instantiate()
var scr_moam = ResourceLoader.load("res://CORE/moam.gd")
var scr_mkdown = ResourceLoader.load("res://CORE/mkdown.gd")
Logger.diag("coreloader","Constructing CORE")
var core = Control.new()
core.name = "core"
core.script = scr_core
Logger.diag("coreloader","Attaching CORE to /root/")
get_tree().root.add_child(core)
Logger.diag("coreloader","Attaching modules")
core.attach("config",scr_config)
core.attach("wmgr",scr_wmgr)
core.attach("smgr",scr_smgr)
core.attach("resmgr",scr_resmgr)
core.attach("events",scr_events)
core.attach("splash",scr_splash,false)
core.attach("moam",scr_moam)
core.attach("mkdown",scr_mkdown)
if core.protection_mode: return
Logger.diag("coreloader","Loading module configurations")
core.wmgr.load_configuration()
core.splash.load_configuration()
core.moam.load_configuration()
Logger.diag("coreloader","Initializing modules")
core.wmgr.initialize()
core.smgr.initialize()
core.resmgr.initialize()
core.events.initialize()
core.splash.initialize()
core.moam.initialize()
core.mkdown.initialize()
Logger.diag("coreloader","Locking CORE")
core.lock()
Logger.diag("coreloader","Waiting for CORE to fully initialize")
while !core.readylized:
await get_tree().create_timer(1).timeout
Logger.diag("coreloader","CORE has been initialized and is ready.")
Logger.diag("coreloader","Preloading project init script")
var initscr = ResourceLoader.load(core.config.core_startscript)
Logger.diag("coreloader","Constructing project init script")
var initscr_obj = Control.new()
initscr_obj.name = "ProjectInitScript"
initscr_obj.set_script(initscr)
Logger.diag("coreloader","Adding project init script to /root/")
get_tree().root.add_child(initscr_obj)
Logger.diag("coreloader","Removing coreloader")
queue_free()

View file

@ -1,38 +1,50 @@
# corelog.gd
# CORE Log
#
# This file is part of StarOpenSource CORE (SOSCORE)
# Made by the StarOpenSource Project and Contributers
# Licensed under GNU GPLv3
extends RichTextLabel
######################################
# 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) #
######################################
extends Node
var log_prefix = ""
var log_suffix = ""
# CORE modules
var core: Node = null
var logger: Node = null
func _ready() -> void:
# Enable recieving of log messages
Logger.connect("logevent",Callable(self,"logevent"))
# Disable VScrollBar functionality & visibility
get_child(0,true).add_theme_stylebox_override("grabber",StyleBoxEmpty.new())
get_child(0,true).add_theme_stylebox_override("grabber_highlight",StyleBoxEmpty.new())
get_child(0,true).add_theme_stylebox_override("grabber_pressed",StyleBoxEmpty.new())
get_child(0,true).add_theme_stylebox_override("scroll",StyleBoxEmpty.new())
get_child(0,true).add_theme_stylebox_override("scroll_focus",StyleBoxEmpty.new())
get_child(0,true).set_deferred("size",Vector2i(0,0))
get_child(0,true).mouse_filter = Control.MOUSE_FILTER_IGNORE
# Make RichTextLabel ignore all mouse events (to disable scrolling)
mouse_filter = Control.MOUSE_FILTER_IGNORE
# Initializes CORELog
func initialize() -> void:
if core.protection_mode: return
# logevent (signal) -> logupdate()
logger.connect("logevent",Callable(self,"logupdate"))
# Activate auto scrolling
$Background/Log.scroll_active = true
$Background/Log.scroll_following = true
# Disable mouse influence
$Background/Log.mouse_filter = Control.MOUSE_FILTER_IGNORE
$Background/Log.get_child(0,true).mouse_filter = Control.MOUSE_FILTER_IGNORE
# Remove every VScrollBar style
$Background/Log.get_child(0,true).add_theme_stylebox_override("grabber",StyleBoxEmpty.new())
$Background/Log.get_child(0,true).add_theme_stylebox_override("grabber_highlight",StyleBoxEmpty.new())
$Background/Log.get_child(0,true).add_theme_stylebox_override("grabber_pressed",StyleBoxEmpty.new())
$Background/Log.get_child(0,true).add_theme_stylebox_override("scroll",StyleBoxEmpty.new())
$Background/Log.get_child(0,true).add_theme_stylebox_override("scroll_focus",StyleBoxEmpty.new())
# Set VScollBar size to zero
$Background/Log.get_child(0,true).set_deferred("size",Vector2i(0,0))
func _process(_delta) -> void:
var windowsize = DisplayServer.window_get_size()
$".".size = windowsize
get_parent().size = windowsize
get_parent().get_parent().size = windowsize
# Updates log text
func logupdate(_type:String,_script:String,_method:String,logmessage:String) -> void:
$Background/Log.text = $Background/Log.text + "\n" + logmessage
func logevent(_type:String,_script:String,_message:String,logcomp:String) -> void:
# Appends log to RichTextLabel
text = text + "\n" + log_prefix + logcomp + log_suffix
# These two functions are very self explanitory
func display() -> void:
if core.protection_mode: return
$Background.visible = true
func rmconnect() -> void:
# Disables recieving of log messages
Logger.disconnect("logevent",Callable(self,"logevent"))
func dissolve() -> void:
if core.protection_mode: return
$Background.visible = false

52
corelog.tscn Normal file
View file

@ -0,0 +1,52 @@
[gd_scene load_steps=5 format=3]
[ext_resource type="Script" path="res://CORE/corelog.gd" id="1_8l1qi"]
[ext_resource type="FontFile" path="res://CORE/hack.ttf" id="1_m5led"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_adeh8"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_koe3t"]
[node name="CORELog" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_8l1qi")
[node name="Background" type="ColorRect" parent="."]
layout_mode = 0
offset_right = 960.0
offset_bottom = 540.0
color = Color(0, 0, 0, 1)
[node name="Log" type="RichTextLabel" parent="Background"]
layout_mode = 0
offset_right = 960.0
offset_bottom = 540.0
theme_override_colors/default_color = Color(1, 1, 1, 1)
theme_override_fonts/normal_font = ExtResource("1_m5led")
theme_override_fonts/bold_font = ExtResource("1_m5led")
theme_override_fonts/italics_font = ExtResource("1_m5led")
theme_override_fonts/bold_italics_font = ExtResource("1_m5led")
theme_override_fonts/mono_font = ExtResource("1_m5led")
theme_override_font_sizes/normal_font_size = 12
theme_override_font_sizes/bold_font_size = 12
theme_override_font_sizes/italics_font_size = 12
theme_override_font_sizes/bold_italics_font_size = 12
theme_override_font_sizes/mono_font_size = 12
theme_override_styles/focus = SubResource("StyleBoxEmpty_adeh8")
theme_override_styles/normal = SubResource("StyleBoxEmpty_koe3t")
bbcode_enabled = true
text = "coreinit -> \"Fixing\" busy setting up children issue
coreinit -> Bootstrapping CORE
coreinit -> Checking CORE requirements
coreinit -> Loading modules
coreinit -> Constructing modules
coreinit -> Injecting modules
coreinit -> Updating dependency references
coreinit -> Applying configuration to base modules
coreinit -> Initializing base modules"
scroll_following = true

View file

@ -1,11 +1,27 @@
#!/bin/bash
if [ "$1" == "--help" ]; then
echo "Environment variables: VERBOSE (false)"
echo " FILEEXTENSION (*)"
echo " IGNORE_SCRIPT (false)"
echo " IGNORE_DOCUMENTATION (false)"
echo " NUMBER_ONLY (false)"
exit 0
fi
function dircount() {
if [ "$VERBOSE" == "true" ]; then echo ":: Checking directory \"$*\"..."; fi
cd "$*" || exit 54
for file in $FILEEXTENSION; do
export "file_full=$*/$file"
if [ -d "$file" ]; then
dircount "$file_full"
if [ "$file" == "devprj" ]; then
if [ "$VERBOSE" == "true" ]; then echo ":: Skipping directory \"devprj\"";fi
else
if [ "$IGNORE_DOCUMENTATION" == "true" ] && [ "$file" == "docs" ]; then
if [ "$VERBOSE" == "true" ]; then echo ":: Skipping directory \"docs\"";fi
else
dircount "$file_full"
fi
fi
elif [ -f "$file" ]; then
if [ "$IGNORE_SCRIPT" == "true" ] && [ "$file" == "count_characters.sh" ]; then
if [ "$VERBOSE" == "true" ]; then echo ":: Skipping this script"; fi

71
debugdisplay.gd Normal file
View file

@ -0,0 +1,71 @@
######################################
# 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) #
######################################
extends Node
# CORE modules
var core: Node = null
var misc: Node = null
# Important nodes
@onready
var display: RichTextLabel = get_node("Display")
# Config
var config_enabled: bool = false
var config_fps: bool = false
var config_delta: bool = false
var config_rendertime: bool = false
var config_memory: bool = false
# Check if enabled
func _process(_delta) -> void:
if config_enabled:
update_display()
display.visible = true
else:
display.visible = false
# Updates the display with useful information
func update_display():
var displaytext: String = ""
var displaysize: int = 17
# Get memory information
var info_memory: Dictionary = OS.get_memory_info()
if config_memory:
info_memory.merge({"peak":OS.get_static_memory_peak_usage(),"percent":float(OS.get_static_memory_usage())/info_memory["physical"]*100,"used":OS.get_static_memory_usage()})
# If fps is enabled, add the fps counter
if config_fps:
displaysize = displaysize+17*1
displaytext = displaytext + "\nFPS: " + str(snappedf(misc.get_fps(false),0.01))
# If delta is enabled, add the delta counter
if config_delta:
displaysize = displaysize+17*1
displaytext = displaytext + "\nDelta: " + str(misc.get_delta())
# If rendertime is enabled, add the rendertime counter
if config_rendertime:
displaysize = displaysize+17*1
displaytext = displaytext + "\nRendertime: " + str(misc.get_rendertime())
# If memory is enabled, display memory information
if config_memory:
displaysize = displaysize+17*2
displaytext = displaytext + "\nMemory (Available|Used|Stack): " + str(misc.byte_to_mib(info_memory["available"],true)) + " MiB|" + str(misc.byte_to_mib(info_memory["used"],true)) + " MiB|" + str(misc.byte_to_mib(info_memory["stack"],true)) + " MiB"
displaytext = displaytext + "\nMemory (Physical|Peak|%): " + str(misc.byte_to_mib(info_memory["physical"],true)) + " MiB|" + str(misc.byte_to_mib(info_memory["peak"],true)) + " MiB|" + str(snappedf(info_memory["percent"],0.001)) + "%"
# Add CORE version and (if enabled) a dev mode notice
if core.development_mode:
displaytext = "CORE " + core.version["full"] + " [color=yellow](development mode)[/color]" + displaytext
else:
displaytext = "CORE " + core.version["full"] + displaytext
# Update display
display.text = displaytext
display.size = Vector2i(540,displaysize)

34
debugdisplay.tscn Normal file
View file

@ -0,0 +1,34 @@
[gd_scene load_steps=5 format=3]
[ext_resource type="Script" path="res://CORE/debugdisplay.gd" id="1_hcfi0"]
[ext_resource type="FontFile" path="res://CORE/hack.ttf" id="1_nhdg1"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_3c08d"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5ghow"]
bg_color = Color(0.839216, 0.0196078, 0.196078, 0.862745)
corner_radius_bottom_right = 16
shadow_color = Color(0, 0, 0, 0)
[node name="DebugDisplay" type="Node"]
script = ExtResource("1_hcfi0")
[node name="Display" type="RichTextLabel" parent="."]
offset_right = 540.0
offset_bottom = 102.0
theme_override_colors/default_color = Color(1, 1, 1, 1)
theme_override_fonts/normal_font = ExtResource("1_nhdg1")
theme_override_font_sizes/normal_font_size = 14
theme_override_font_sizes/bold_font_size = 14
theme_override_font_sizes/italics_font_size = 14
theme_override_font_sizes/bold_italics_font_size = 14
theme_override_font_sizes/mono_font_size = 14
theme_override_styles/focus = SubResource("StyleBoxEmpty_3c08d")
theme_override_styles/normal = SubResource("StyleBoxFlat_5ghow")
bbcode_enabled = true
text = "CORE source-N (development mode) (THIS IS A PLACEHOLDER!)
FPS:
Delta:
Rendertime:
Memory (1):
Memory (2):"

9
docs/breaking-commits.md Normal file
View file

@ -0,0 +1,9 @@
---
hide:
- navigation
---
# Breaking commits
We sometimes push a commit that may break something for some project. Here's where we list critical changes.
## 404 Documentation not found
There are no breaking commits as of now.

View file

@ -6,16 +6,16 @@ hide:
Welcome to the StarOpenSource documentation! Look below for more information about CORE and code references.
## What, why, wtf?
The **StarOpenSource CORE Framework** (also known as **CORE** or **SOSCORE**) is a framework that makes the development of games and applications written in **Godot 4.0 and 4.1** easier. CORE implements useful & common functions *(such as calculating the current FPS)* and provides a logging system that even supports formatting, a scene manager and so much more.
The **StarOpenSource CORE Framework** (also known as **CORE** or **SOSCORE**) is a framework that makes the development of games and applications written in **Godot 4.1** easier. CORE implements useful & common functions *(such as calculating the current FPS)* and provides a logging system that even supports formatting, a scene manager and so much more.
## Can I use CORE in my existing project?
In theory, yes. But if you don't want to refactor a large part of your codebase, don't install CORE.
Yes, unless you want to refactor your entire project. Remember: CORE is a framework, NOT a library and NOT a regular addon!
## Can I use CORE in my project freely?
[Click this text to learn more about licensing.](/licensing/)
## I have a problem with CORE!
First of all, read the [Troubleshooting guide](/troubleshooting/). If you can't find your error or it's some incompatibility with CORE and project x, [create a issue](https://git.staropensource.de/StarOpenSource/core/issues/new).
First of all, read the [Troubleshooting guide](/troubleshooting/). If you can't find your error in there or CORE has a compatibility issue with some addon, look at [the issue tracker](https://git.staropensource.de/StarOpenSource/issues) for more information.
## How to install/update CORE?
If you want to install CORE, follow [this guide](/install/). If you want to update CORE to the latest version instead, follow [this guide](/update/) instead.

View file

@ -3,66 +3,131 @@ hide:
- navigation
---
# Installing CORE
## Step 1: Downloading the *CORE Manager*
## The safe route
### Step 1: Downloading the *CORE Manager*
Before we install CORE, we first have to download the **CORE Manager**. It is responsible for installing CORE and downloading updates.<br/>
#### Windows: [CORE-Manager.exe](https://git.staropensource.de/staropensource/core-manager/releases/download/b0/CORE-Manager.exe)
#### Linux: [CORE-Manager.elf](https://git.staropensource.de/staropensource/core-manager/releases/download/b0/CORE-Manager.elf)
#### Windows: [CORE-Manager.exe](https://git.staropensource.de/staropensource/core-manager/releases/download/b1/CORE-Manager.exe)
#### Linux: [CORE-Manager.elf](https://git.staropensource.de/staropensource/core-manager/releases/download/b1/CORE-Manager.elf)
#### macOS: Use `wine` to run `CORE-Manager.exe`
## Step 2: Using the *CORE Manager*
### Step 2: Using the *CORE Manager*
Launch `CORE-Manager.exe` or `CORE-Manager.elf` and type in the path to your Godot project ***(replace backslashes with regular slashes on Windows)***. Click on `Install` and wait until it's finished.
**Note: If you are updating CORE, click on `Update` instead.**
## Step 3: Configuring your project
### Step 3: Configuring your project
Launch your project in the Godot Editor and go to your project settings. You now need to set your startup scene to `res://CORE/coreinit.tscn`.
## Step 4: Configuring CORE
Edit the `res://CORE/config.gd` file and set the `core_startscript` variable to a GDScript file. That GDScript file will act as your init script and can be used to load your game. You can find the `config.gd` reference [here](/references/config.gd/).
## Step 5: Write your init script
Create a new GDScript file and write this into it:
``` gdscript
### Step 4: Write your init script
Create a new GDScript file at `res://init.gd` (can be anything else, but you need to change the `core_initscript` variable accordingly!) and write this into it:
```gdscript
extends Node
@onready
var core = get_node("/root/core") #(1)!
var core = get_node("/root/CORE") #(1)!
@onready
var logger = core.get_module("Logger") #(2)!
func _ready() -> void:
core.welcome() #(2)!
Logger.enable_diag = true #(3)!
Logger.diag("<your_script_name>","This is a diagnostic message. I can only be seen with Logger.enable_diag being true.")
Logger.info("<your_script_name>","This is a informational message.")
Logger.warn("<your_script_name>","This is a warning message.")
Logger.error("<your_script_name>","This is a error message.")
await get_tree().create_timer(0.1).timeout #(4)!
get_tree().quit(0)
core.welcome() #(3)!
config.logger_diagnostic = true #(4)!
core.reload_config() #(5)!
logger.diag("<your_script_name>","This is a diagnostic message. I can only be seen if diagnostic log messages are enabled.")
logger.info("<your_script_name>","This is a informational message.")
logger.warn("<your_script_name>","This is a warning message.")
logger.error("<your_script_name>","This is a error message.")
core.exit_safely() #(6)!
```
1. Imports the CORE Holder aka. /root/core
2. Makes CORE say hello :)
3. Enables diagnostic log output
4. Waits 100 milliseconds for the log messages to be printed before exiting
1. Imports the CORE "module" aka. /root/CORE
2. Imports the CORE's logger implementation
3. Makes CORE say hello :)
4. Overwrites the logger_diagnostic setting temporarily (in memory)
5. Applies all modified settings
6. Tells CORE to shutdown your application safely. Has to do with CORE's logger and Godot.
Now replace `<your_script_name>` with the filename of your script (without `.gd`) and save it under the path you specified in the `core_startscript` variable.
Now replace `<your_script_name>` with the file path of your script (preferably with `.gd` and without `res://`) and save it under the path you specified in the `core_initscript` variable.
## Step 6: Start your project
Start your project and wait until CORE initialized itself. You should see this output in your Godot console (replace `<your_script_name>` in your head with the filename of the init script without `.gd`):
``` text
logger -> Initializing Logger
preprocessor -> Initializing Preprocessor
preprocessor -> Delaying initialization by 0.75s
### Step 5: Start your project
Start your project and wait at least 500ms. You should see this output in your Godot console (with a few variations, of course):
```text
coreinit -> "Fixing" busy setting up children issue #(1)!
coreinit -> Bootstrapping CORE
coreinit -> Checking CORE requirements
coreinit -> Constructing coreloader
coreinit -> Injecting coreloader
coreinit -> Switching to COREBackground
(core) [INFO] CORE git-develop welcomes you!
It seems like everything is working :)
(<your_script_name>) [DIAG] This is a diagnostic message. I can only be seen with Logger.enable_diag being true.
(<your_script_name>) [INFO] This is a informational message.
(<your_script_name>) [WARN] This is a warning message.
(<your_script_name>) [ERROR] This is a error message.
(coreloader) [DIAG] Removing coreloader
coreinit -> Loading modules
coreinit -> Constructing modules
coreinit -> Injecting modules
coreinit -> Updating dependency references
coreinit -> Applying configuration to base modules
coreinit -> Initializing base modules
(CORE/core.gd) [INFO] CORE (source 0) welcomes you! #(2)!
It seems like everything is working :)
(init.gd) [DIAG] This is a diagnostic message. I can only be seen if diagnostic log messages are enabled.
(init.gd) [INFO] This is a informational message.
(init.gd) [WARN] This is a warning message.
(init.gd) [ERR!] This is a error message.
(CORE/coreinit.gd) [DIAG] Bootstrapped CORE, exiting. #(3)!
```
If your project returns about the same output (a few lines omitted) then CORE has been successfully installed. If not, look for your error [here](/troubleshooting/). If you need a example `init.gd` script, [look here](/references/init.gd/).
1. These messages are printed anyway as CORE's logger implementation is not loaded at that point in time
2. That log messages comes from your init.gd!
3. tldr we enabled diagnostic messages "too fast". if we delayed the config reload by half a second, we wouldn't have seen that message.
If your project returns about the same output then CORE has been successfully installed. If not, look for your error [here](/troubleshooting/). For a quick start guide, [click here](/quickstartguide/)
## YOLOing the install
Do you want to play with fire? Do you like to live at the edge of what's possible? Or are you just a Arch Linux or Gentoo user? If yes, here's a guide on how to manually install and update CORE.
### Note
This install method is **only recommended for devs experienced with CORE, Godot 4 and Git**. We are not responsible if you mess up something and break your project!
### Installing CORE
1. Create your Godot Project and open the project folder in a terminal
2. Execute `git clone https://git.staropensource.de/StarOpenSource/core.git CORE` (even if you're planning/using a git repository already! Do NOT use git submodules!)
3. `cd` into the CORE folder and copy `config.gd.example` and rename it to `config.gd`. You may edit it to your liking now.
4. Create your init script at `[project root]/init.gd` (or some other path, update it in `config.gd` accordingly) and write this into it:
```gdscript
extends Node
@onready
var core = get_node("/root/CORE")
@onready
var logger = core.get_module("Logger")
func _ready() -> void:
logger.info("init.gd","init.gd loaded.")
core.welcome()
core.exit_safely()
```
5. Go back to Godot and set your startup scene to `res://CORE/coreinit.tscn`
6. Launch your project, you should see something like this in your console:
```text
coreinit -> "Fixing" busy setting up children issue
coreinit -> Bootstrapping CORE
coreinit -> Checking CORE requirements
coreinit -> Loading modules
coreinit -> Constructing modules
coreinit -> Injecting modules
coreinit -> Updating dependency references
coreinit -> Applying configuration to base modules
coreinit -> Initializing base modules
(init.gd) [INFO] init.gd loaded.
(CORE/core.gd) [INFO] CORE (source 0) welcomes you!
It seems like everything is working :)
(CORE/coreinit.gd) [DIAG] Bootstrapped CORE, exiting.
```
7. Congrats, you're not a idiot.
### Updating CORE
1. Open your Godot project folder in a terminal
2. `cd` into the CORE folder and create a backup of your `config.gd` file
3. Run `git pull`
4. Check the [breaking commits](/breaking-commits/) documentation page for breaking changes and update your code accordingly
5. Launch your project and look for any issues. If any arise re-check your code for any [breaking commits](/breaking-commits/) or contact us.
### Reverting a update
#### Reverting an update is unsupported and should **only** be used in special cases.
1. Open your Godot project folder in a terminal
2. `cd` into the CORE folder and create a backup of your `config.gd` file
3. Run `git fetch && git checkout <COMMIT>` (replace `<COMMIT>` with whatever commit you want to revert to)
4. Revert all changes made in all commits after. Checking the [breaking commits](/breaking-commits/) page might be useful.

View file

@ -7,7 +7,7 @@ hide:
This documentation page only covers the most important licensing question. If you want to read more about the GNU General Public License Version 3, [read this](https://www.gnu.org/licenses/gpl-faq.html).
## Note
Under **modified CORE copy** we understand a CORE installation that has been modified in any way (**config.gd** is excluded). If you modified anything else than the **config.gd** file in the **res://CORE/** folder, you have a modified CORE copy.
Under a **modified CORE copy** we understand a CORE installation that has been modified in any way. The configuration file `config.gd` is excluded.
## What happens when the license is violated against?
We'll contact the person/organisation doing that. If they won't take it down or can't be contacted, we'll send a cease and desist letter or contact a lawyer.

57
docs/quickstartguide.md Normal file
View file

@ -0,0 +1,57 @@
---
hide:
- navigation
---
# Quick Start Guide
Welcome to the CORE quick start guide! Here you'll learn how to use CORE efficently and how to start your journey with CORE.
## Note
Please do **NOT** continue if CORE is not installed or not working for you. You can install CORE by [visiting this guide](/install/)
## WARNING
**This quick start guide is work in progress and will heavily change over time. The information at this point in time is accurate but incomplete.**
## Introduction I: The configuration file
The configuration file can be used to configure CORE to your liking and tweak it's behaviour. You can edit the configuration **permanently** in `res://CORE/config.gd` or **overwrite** the config **temporarily** ***in memory*** using this example:
```gdscript
extends Node
@onready
var core: Node = get_node("/root/CORE")
@onready
var config: Node = core.get_module("Config") #(1)!
func _ready() -> void:
logger.diag("init.gd","This diagnostic message will be hidden unless enabled permanently.") #(2)!
config.logger_diagnostic = true #(3)!
core.reload_config() #(4)!
logger.diag("init.gd","This diagnostic message will be displayed even if disabled permanently as we overwrote the setting in memory.") #(5)!
```
1. Imports the config module for configuration access
2. Will be hidden unless logger_diagnostic is set to true permanently
3. Overwrites the configuration setting "logger_diagnostic" in memory
4. Tells CORE to apply config changes
5. Will be displayed even if logger_diagnostic is set to false permanently as we overwrote the value in memory and set it to true
```
## Introduction II: The init script
The initialization script (you specified in the configuration file) is injected into the SceneTree after CORE completed it's startup procedure. Your init script is responsible for loading and displaying your application. Here's a basic example of `res://init.gd` loading a scene located at `res://testscene.tscn` and freeing itself.
```gdscript
extends Node
@onready
var core: Node = get_node("/root/CORE")
@onready
var resourcemanager: Node = core.get_module("ResourceManager")
@onready
var scenemanager: Node = core.get_module("SceneManager")
func _ready() -> void:
logger.info("init.gd","Loading testscene")
resourcemanager.load("testscene","res://testscene.tscn")
logger.info("init.gd","Injecting testscene into SceneTree under the action overlay.")
scenemanager.add_game("testscene")
logger.info("init.gd","Removing init script")
queue_free()
```

57
docs/references/CORE.md Normal file
View file

@ -0,0 +1,57 @@
---
hide:
- navigation
---
# CORE (/root/CORE)
The main "module"
## Constants
### version
- type `Dictionary`
- description `The CORE version. "type" is the release type, "releasebuild" the number of the latest release and "full" the full version string.`
- keys `type` (`String`, either `source`, `release` or `prerelease`), `releasebuild` (`int`) and `full` (`String`)
## Enums
### Errors
- description `Contains all possible errors CORE can throw at you.`
- keys `OK`, `CORE_PROTECTIONMODE`, `CORE_EXCEPTION`, `CORE_INVALID_MODULE`, `RESOURCEMANAGER_ALREADY_EXISTS`, `RESOURCEMANAGER_RESOURCE_MISSING`, `RESOURCEMANAGER_BATCH_EMPTY`, `SCENEMANAGER_ALREADY_LOADED`, `SCENEMANAGER_NOT_LOADED` and `SCENEMANAGER_NOT_PACKEDSCENE`
## Methods
### welcome()
- returns `void`
- description `Prints a welcome message and the CORE version.`
### reload_config()
- returns `void`
- description `Reloads the configuration file and applies any changes (made in memory).`
### get_module()
- returns `Node`
- description `Returns a CORE module. A alternative to get_node("/root/CORE/<module>")`
- argument `module_name`
- type `StringName`
- mandatory `yes`
- description `The CORE module that should be returned`
- possible values `Config`, `Preprocessor`, `Logger`, `Miscellaneous`, `DebugDisplay`, `SplashScreen`, `ResourceManager`, `SceneManager` and `Events`
- example
```gdscript
extends Node
@onready
var core = get_node("/root/CORE")
@onready
var logger = core.get_module("Logger")
func _ready() -> void:
logger.info("test.gd","Hi there!")
```
### devmode()
- returns `void`
- description `Enables the development mode`
- note `Do not call this function unless you're working on CORE. It disables limits and many more things.`
### exit_safely()
- returns `void`
- description `Exists CORE safely. Is recommended over get_tree().quit() as log messages may be stuck in processing and would get lost otherwise.`
- argument `exitcode`
- type `int`
- description `Oh, you don't know what an exitcode is? Learn cmd.exe or bash you fool!`
- mandatory `no, default value is 0`
- trivia `The only thing this method does is to enable CORE's protection mode, wait 500ms (0.5s) and then quit.`

View file

@ -0,0 +1,142 @@
---
hide:
- navigation
---
# Configuration File (/root/CORE/Config)
The CORE configuration file is located at `res://CORE/config.gd` and is used for configuring CORE behaviour. A full example configuration can be found [here](#example-configuration).
## Placeholders
### [LOADPATH]
- type `String`
- description `Will be replaced by CORE's loadpath`
- example `res://CORE/`
- can be used in `splash_image`
## CORE
### core_initscript
- type `String`
- description `The path to your init script`
- default value `"res://init.gd"`
## Preprocessor
### preprocessor_enabled
- type `bool`
- description `Enables the preprocessor if true`
- default value `true`
### preprocessor_diagnostic
- type `bool`
- description `Makes the preprocessor super-verbose`
- default value `false`
- note `Please leave this option disabled as your log will get massively bloated by the preprocessor.`
## Logger
### logger_enabled
- type `bool`
- description `Enables CORE's logger implementation if true`
- default value `true`
### logger_diagnostic
- type `bool`
- description `Displays diagnostic messages including messages by CORE if enabled.
- default value `false`
## CORELog
### corelog_enabled
- type `bool`
- description `If CORELog should be displayed or not`
- default value `true`
## Debug Display
### debugdisplay_enabled
- type `bool`
- description `If the debug display should be enabled or not`
- default value `false`
### debugdisplay_fps
- type `bool`
- description `Displays the framerate counter if true`
- default value `true`
### debugdisplay_delta
- type `bool`
- description `Renders the delta value if true`
- default value `true`
### debugdisplay_rendertime
- type `bool`
- description `Displays the rendertime if true`
- default value `true`
### debugdisplay_memory
- type `bool`
- description `Displays information about the memory usage if true`
- default value `true`
## Resource Manager
## resourcemanager_load_invalid_file_as_null
- type `bool`
- description `Affects the Resource Manager's loadres() function if it encounters a invalid filepath. If true, loadres() will "save" the resource as null, but will do nothing if false.`
- default value `false`
## Splash Screen
### splash_enabled
- type `bool`
- description `Enables or disables the splash screen at startup`
- default value `false`
- note `You can still call display() and dissolve() manually, this option just affects the startup process.`
### splash_image
- type `String`
- description `The path to your splash image (square-sized)`
- default value `[LOADPATH]soscore.png`
### splash_image_size
- type `int`
- description `The width and height of your square-sized image`
- default value `256`
### splash_color
- type `String`
- description `The splash screen's background color in hex (without the "#" at the beginning!)`
## Example configuration
This is the full example configuration that you can find as `config.gd.example`
```gdscript
##############################
# THE CORE FRAMEWORK #
# EXAMPLE CONFIGURATION FILE #
# #
# THIS DOCUMENT IS PUBLICLY #
# AVAILABLE UNDER THE PUBLIC #
# DOMAIN AND IS NOT LICENSED #
##############################
extends Node
# Hello there, fellow developer!
# This is a example configuration file
# for the CORE Framework (source 0).
#
# Most settings in this config should be
# self explanitory. If not, visit the documentation:
# https://core.staropensource.de/references/Configuration_File/
#
# Thank you for using the CORE Framework!
# - The StarOpenSource Project & Contributers
var core_initscript: String ? "res://init.gd"
var preprocessor_enabled: bool = true
var preprocessor_diagnostic: bool = false
var logger_enabled: bool = true
var logger_diagnostic: bool = false
var corelog_enabled: bool = true
var debugdisplay_enabled: bool = false
var debugdisplay_fps: bool = true
var debugdisplay_delta: bool = true
var debugdisplay_rendertime: bool = true
var debugdisplay_memory: bool = true
var resourcemanager_load_invalid_file_as_null: bool = false
var splash_enabled: bool = false
var splash_image: String = "res://CORE/soscore.png"
var splash_image_size: int = 256
var splash_color: String = "000000"
# EOF <- Yes, this is the end of the example configuration! Pretty short, isn't it?
```

View file

@ -0,0 +1,9 @@
---
hide:
- navigation
---
# Debug Display (/root/CORE/DebugDisplay)
Displays useful information in the top-left corner
## 404 Documentation not found
The `Debug Display` module does not have any variables or methods that are relevant to a developer as you can change everything through the configuration file.

43
docs/references/Events.md Normal file
View file

@ -0,0 +1,43 @@
---
hide:
- navigation
---
# Events (/root/CORE/Events)
Just connect a signal to a function and get updates when something happens
## Signals
### window_title
- emitted on `window title change`
- argument `window_title` (type `String`)
- argument `previous_window_title` (type `String`)
### window_size
- emitted on `window size change`
- argument `update_coordinate` (type `String`, can be `X`, `Y` or `BOTH`)
- argument `window_size` (type `Vector2i`)
- argument `previous_window_size` (type `Vector2i`)
### window_pos
- emitted on `window position change`
- argument `update_coordinate` (type `String`, can be `X`, `Y` or `BOTH`)
- argument `window_pos` (type `Vector2i`)
- argument `previous_window_pos` (type `Vector2i`)
### logger_all
- emitted on `log output`
- argument `type` (type `String`, can be `"DIAG"`, `"INFO"`, `"WARN"` or `"ERROR"`)
- argument `script` (type `String`)
- argument `message` (type `String`)
### logger_diag
- emitted on `diagnostic log output`
- argument `script` (type `String`)
- argument `message` (type `String`)
### logger_info
- emitted on `informational log output`
- argument `script` (type `String`)
- argument `message` (type `String`)
### logger_warn
- emitted on `warning log output`
- argument `script` (type `String`)
- argument `message` (type `String`)
### logger_error
- emitted on `error log output`
- argument `script` (type `String`)
- argument `message` (type `String`)

76
docs/references/Logger.md Normal file
View file

@ -0,0 +1,76 @@
---
hide:
- navigation
---
# Logger (/root/CORE/Logger)
The CORE logger implementation (with formatting support!)
## Signals
### logevent
- emitted on `log message`
- argument `type` (type `String`, can be `DIAG`, `INFO`, `WARN` or `ERR!`)
- argument `script` (type `String`)
- argument `message` (type `String`)
- argument `logmessage` (type `String`, description `The full log message as printed in console`)
## Methods
### diag()
- returns `void`
- description `Prints a diagnostic message`
- argument `script`
- type `String`
- mandatory `yes`
- description `The script where the log message is coming from`
- argument `message`
- type `String`
- mandatory `yes`
- description `Your log message`
- argument `preproc`
- type `bool`
- mandatory `no, default value is true`
- description `If the log message should be run through the preprocessor. If false formatting will be disabled for that log message.`
### info()
- returns `void`
- description `Prints a informational message`
- argument `script`
- type `String`
- mandatory `yes`
- description `The script where the log message is coming from`
- argument `message`
- type `String`
- mandatory `yes`
- description `Your log message`
- argument `preproc`
- type `bool`
- mandatory `no, default value is true`
- description `If the log message should be run through the preprocessor. If false formatting will be disabled for that log message.`
### warn()
- returns `void`
- description `Prints a warning message`
- argument `script`
- type `String`
- mandatory `yes`
- description `The script where the log message is coming from`
- argument `message`
- type `String`
- mandatory `yes`
- description `Your log message`
- argument `preproc`
- type `bool`
- mandatory `no, default value is true`
- description `If the log message should be run through the preprocessor. If false formatting will be disabled for that log message.`
### error()
- returns `void`
- description `Prints a error message`
- argument `script`
- type `String`
- mandatory `yes`
- description `The script where the log message is coming from`
- argument `message`
- type `String`
- mandatory `yes`
- description `Your log message`
- argument `preproc`
- type `bool`
- mandatory `no, default value is true`
- description `If the log message should be run through the preprocessor. If false formatting will be disabled for that log message.`

View file

@ -0,0 +1,51 @@
---
hide:
- navigation
---
# Miscellaneous (/root/CORE/Miscellaneous)
Contains small methods that do not deserve their own module.
## Methods
### get_title()
- returns `String`
- description `Returns the main window title.`
- note `This method simply returns the value of get_tree().root.title and is included here as DisplayServer.window_get_title() does not exist.`
### get_fps()
- returns `float`
- description `Returns the current framerate aka. FPS aka. Frames Per Second`
- note `If the delta value (which is used in the calculation) is zero, INF (infinity) will be returned.`
- argument `flatten`
- type `bool`
- mandatory `no, default value is false`
- description `The decimal numbers will be removed if true`
### get_rendertime()
- returns `float`
- description `Returns the time in milliseconds it took for Godot to render a frame`
### get_delta()
- returns `float`
- description `Returns the delta value you normally see as a argument in _process()`
### byte_to_mib()
- returns `float`
- description `Converts a number of bytes to a number of Mebibytes.`
- argument `bytes`
- type `int`
- mandatory `yes`
- description `The number of bytes`
- argument `flatten`
- type `bool`
- mandatory `no, default value is true`
- description `The decimal numbers will be removed if true`
## flat_float()
- returns `float`
- description `Removes all decimal numbers from a floating point number.`
- argument `number`
- type `float`
- mandatory `yes`
- description `The floating point number`
## flat_float_int()
- returns `int`
- description `Removes all decimal numbers from a floating point number. Returns a integer instead of a float`
- argument `number`
- type `float`
- mandatory `yes`
- description `The floating point number`

View file

@ -0,0 +1,96 @@
---
hide:
- navigation
---
# Preprocessor (/root/CORE/Preprocessor)
The **Preprocessor** parses tags and is responsible for formatting text.
## Tags *(these can be used in log messages too!)*
All tags can be escaped by adding `esc_` before the tag name, if you want to do that. Example:
```text
Raw: <esc_up><esc_np></esc_lo>
Output: <up><np></lo>
```
### No process `<np>`
- end tag `no`
- description `Disables preprocessing completely. Doesn't even display the prefix.`
- example:
``` text
Raw: <up>This is a</up><pa>test</pa><np> MESS<lo>age</lo>.
Output: <up>This is a</up><pa>test</pa> MESS<lo>age</lo>.
```
### Newline `<nl>`
- end tag `no`
- description `Makes a newline while respecting the prefix. Is much recommended over "\n".`
- example (with prefix `prefix_`):
``` text
Raw: Very nice message!<nl>Here's another message :)
Output:
prefix_Very nice message!
Here's another message :)
```
### Lowercase `<lo></lo>`
- end tag `yes`
- description `Makes your text lowercase.`
- example:
``` text
Raw: Did <lo>you FiNd THA</lo>T funny?
Output: Did you find thaT funny?
```
### Uppercase `<up></up>`
- end tag `yes`
- description `Makes your text uppercase.`
- example:
``` text
Raw: ThiS Te<up>XT should be UPPer</up>caSED
Output: ThiS TeXT SHOULD BE UPPERcaSED
```
### Camelcase `<ca></ca>`
- end tag `yes`
- description `Makes your text camelcase.`
- example:
``` text
Raw: This <ca>text should be CamelCa</ca>sed.
Output: This textShouldBeCamelCased.
```
### Pascalcase `<pa></pa>`
- end tag `yes`
- description `Makes your text pascalcase.`
- example:
``` text
Raw: This <pa>text should be PascelCa</pa>sed.
Output: This TextShouldBePascelCased.
```
### Snakecase `<sn></sn>`
- end tag `yes`
- description `Makes your text snakecase.`
- example:
``` text
Raw: This <sn>text should be SnakeCa</sn>sed.
Output: This text_should_be_snake_cased.
```
## Methods
### process()
- returns `String`
- description `Formats a message`
- argument `msg`
- type `String`
- mandatory `yes`
- description `The message used for processing`
- argument `prefix`
- type `String`
- mandatory `yes`
- description `The prefix used for newlines`
- argument `pre_msg`
- type `String`
- mandatory `no, default value is ""`
- description `Inserted before the message`
- argument `post_msg`
- type `String`
- mandatory `no, default value is ""`
- description `Inserted after the message`
- argument `exclusion_filter`
- type `Array`
- mandatory `no, default value is []`
- description `Removes specific Strings from the prefix (used in calculating spaces when using <nl>)`

View file

@ -2,7 +2,7 @@
hide:
- navigation
---
# Resource Manager (core.resmgr)
# Resource Manager (/root/CORE/ResourceManager)
Responsible for loading and unloading resources, even in batches.
## Methods
@ -54,17 +54,3 @@ Responsible for loading and unloading resources, even in batches.
- type `String`
- mandatory `yes`
- description `The resource name.`
## Internal variables
Do not touch or you will cause breakage.
### resources
- type `Directory`
- default value `{}`
- description `All loaded resources`
- format `{"resource_name":loaded_resource}
## Internal methods
Do not execute or you will cause breakage.
### _ready()
- returns `void`
- description `Executes core.setready(). That's all.`

View file

@ -0,0 +1,79 @@
---
hide:
- navigation
---
# Scene Manager (/root/CORE/SceneManager)
Responsible for displaying scenes using overlays.
## Overlays
The scene manager uses something called **overlays**. A overlay can either hold one scene or multiple scenes and are used to keep scenes in order.
### Overlay #1 - `debug`
- description `The overlay with the highest priority and is displayed over all other overlays. Should contain debug scenes.`
- more than one scene `yes`
- adding a scene **[add_debug()](#add_debug)**
- removing a scene **[remove_debug()](#remove_debug)**
### Overlay #2 - `cutscene`
- description `Has the second highest priority and is displayed over all overlays except debug. Should contain... well cutscenes.`
- more than one scene `no`
- adding a scene **[add_cutscene()](#add_cutscene)**
- removing a scene **[remove_cutscene()](#remove_cutscene)**
### Overlay #3 - `menu`
- description `The overlay with the second lowest priority. Should contain menus.`
- more than one scene `yes`
- adding a scene **[add_menu()](#add_menu)**
- removing a scene **[remove_menu()](#remove_menu)**
### Overlay #4 - `action`
- description `Has the lowest priority. This overlay should contain your main menu, your program's main interface or your level.`
- more than one scene `no`
- adding a scene **[add_action()](#add_action)**
- removing a scene **[remove_action()](#remove_action)**
## Methods
### add_debug()
- returns `bool`
- description `Adds a PackedScene to the debug overlay.`
- argument `resource_name`
- type `String`
- mandatory `yes`
- description `Used for loading the scene and the loaded scene name.`
### remove_debug()
- returns `bool`
- description `Removes a menu scene from the debug overlay.`
- argument `scene_name`
- type `String`
- mandatory `yes`
- description `Should be the same as the "resource_name" argument used previously in add_debug().`
### add_cutscene()
- returns `bool`
- description `Adds a PackedScene to the cutscene overlay.`
- argument `resource_name`
- type `String`
- mandatory `yes`
- description `Used for loading the scene and the loaded scene name.`
### remove_cutscene()
- returns `bool`
- description `Removes the game scene from the cutscene overlay.`
### add_menu()
- returns `bool`
- description `Adds a PackedScene to the menu overlay.`
- argument `resource_name`
- type `String`
- mandatory `yes`
- description `Used for loading the scene and the loaded scene name.`
### remove_menu()
- returns `bool`
- description `Removes a menu scene from the menu overlay.`
- argument `scene_name`
- type `String`
- mandatory `yes`
- description `Should be the same as the "resource_name" argument used previously in add_menu().`
### add_action()
- returns `bool`
- description `Adds a PackedScene to the action overlay.`
- argument `resource_name`
- type `String`
- mandatory `yes`
- description `Used for loading the scene and the loaded scene name.`
### remove_action()
- returns `bool`
- description `Removes the game scene from the action overlay.`

View file

@ -0,0 +1,14 @@
---
hide:
- navigation
---
# Splash Screen (/root/CORE/SplashScreen)
Allows you to display a nice loading screen.
## Methods
### display()
- returns `void`
- description `Makes the splash screen visible.`
### dissolve()
- returns `void`
- description `Makes the splash screen invisible.`

View file

@ -1,130 +0,0 @@
---
hide:
- navigation
---
# CORE configuration file (core.config)
The CORE configuration file is located at `res://CORE/config.gd` and is used for configuring CORE behaviour. A full example configuration can be found [here](#example-configuration).
## CORE
### core_startscript
- type `String`
- default value `res://init.gd`
- description `The initialization script. It is responsible for loading your application and for example displaying a main menu.`
## Window manager (wmgr)
### wmgr_size_x
- type `int`
- default value `960`
- description `The window size set at startup (x coordinate).`
### wmgr_size_y
- type `int`
- default value `540`
- description `The window size set at startup (y coordinate).`
### wmgr_title
- type `String`
- default value `"Application/Game using CORE"`
- description `The window title set at startup.`
### wmgr_mode
- type `String`
- default value `0`
- description `The window mode set at startup.`
- format `0` = `WINDOWED`, `1` = `MINIMIZED`, `2` = `MAXIMIZED`, `3` = `FULLSCREEN` or `4` = `EXCLUSIVE_FULLSCREEN`
## Splash screen (splash)
### splash_enabled
- type `bool`
- default value `false`
- description `Displays or hides the splash screen at startup time.`
- format `true` = `displayed` or `false` = `hidden`
### splash_image
- type `String`
- default value `"res://CORE/soscore.png"`
- description `The path to a image, displayed in the center of the splash screen.`
### splash_image_size
- type `float`
- default value `256`
- description `The size of your image. Used for both the x and y coordinates.`
### splash_color
- type `String`
- default value `000000`
- description `The background color.`
- format `AARRGGBB` or `RRGGBB` (`AA` = `alpha`, `RR` = `red`, `GG` = `green` and `BB` = `blue`)
## Example configuration
This configuration can be found at `res://CORE/config.gd.example`.
``` gdscript
# core.gd.example
# CORE example configuration file
#
# This file is part of StarOpenSource CORE (SOSCORE)
# Made by the StarOpenSource Project and Contributers
# Available in the public domain.
extends Node
# Hello fellow dev! This is the CORE configuration file.
# This file can be used to customize CORE to your liking.
# You do not need to modify any CORE script as some things
# might break (everything depends on each other).
# Thank you for using CORE :)
# CORE
## core_startscript
## Type: String
## Default value: "res://"
## Enter the path to the game/application
## start script. It will be responsible
## for loading your game or application.
var core_startscript = "res://"
# wmgr (Window Manager)
## wmgr_size_x
## Type: int
## Default value: 960
## Defines the default window size (x axis)
var wmgr_size_x = 960
## wmgr_size_y
## Type: Int
## Default value: 540
## Defines the default window size (y axis)
var wmgr_size_y = 540
## wmgr_title
## Type: String
## Default value: "Application/Game using CORE"
var wmgr_title = "Application/Game using CORE"
## wmgr_mode
## Type:int
## Default value: 0
## ID | Mode
## 0 | Windowed
## 1 | Minimized
## 2 | Maximized
## 3 | Fullscreen
## 4 | Exclusive fullscreen
var wmgr_mode = 0
# Splash
## splash_enabled
## Type: bool
## Default value: false
## Enables or disables the splash screen at startup.
## Can be manually enabled with core.splash.display()
var splash_enabled = true
## splash_image
## Type: String
## Default value: "res://CORE/soscore.png"
## The path to your image that will be displayed
## in the center of the splash screen.
var splash_image = "res://CORE/soscore.png"
## splash_image_size
## Type: float
## Default value: 256
## The size of your splash image. Used for both x and y.
var splash_image_size = 256
## splash_color
## Type: String
## Default value: "000000"
## The splash screen's background color. Do not include
## a "#" at the start.
var splash_color = "000000"
```

View file

@ -1,59 +0,0 @@
---
hide:
- navigation
---
# CORE Holder (core)
The **CORE Holder** is responsible for... well holding the components.
## Constants
### version
- type `string`
- description `The CORE version.`
- format `<TYPE> <BUILD>` (`<TYPE>` can be either `release`, `prerelease` or `source`. `<BUILD>` is the latest version number)
## Methods
### welcome()
- returns `void`
- description `Prints a welcome message and the CORE version.`
## Internal Variables
Do not touch or you will cause breakage.
### locked
- type `bool`
- default value `false`
- description `If true, attach() will reject new components.`
### readycount
- type `int`
- default value `0`
- description `How many components have been fully initialized.`
### readylized
- type `bool`
- default value `false`
- description `If all components have been fully initialized. Is set to true if readycount is equal to the number of components.`
## Internal functions
Do not call or you will cause breakage.
### attach()
- returns `void`
- description `Attaches a component to the CORE holder`
- argument `type`
- type `String`
- mandatory `yes`
- description `The component type. Can be "config", "wmgr", "smgr", "resmgr", "events" or "splash".`
- argument `component`
- type `none (intended types are "PackedScene" or "Script")`
- mandatory `yes`
- description `The component attach() should add to the SceneTree.`
- argument `do_setup`
- type `bool`
- mandatory `no, default value is true`
- description `If true, creates a new Control and sets the component as a script. Used for Scripts like "smgr.gd" but not for PackedScene's like "splash.tscn".`
### lock()
- returns `void`
- description `Sets the "locked" variable to true.`
### setready()
- returns `void`
- description `Increases "readycount" variable by 1 and checks if "readycount" is equal to the number of components.`
# Trivia
- The variable [readylized](#readylized) was named like that because a signal called `ready` already exists in `Node` and can therefore not be used as a name. [JeremyStar™](https://git.staropensource.de/JeremyStarTM) then simply appended `lized` from `initialized` to `ready` and `readylized` was born.

View file

@ -1,96 +0,0 @@
---
hide:
- navigation
---
# Events (core.events)
The **Events** component makes tracking changes in your application/game easier.
## Signals
### window_title
- emitted on `window title change`
- argument `window_title` (type `String`)
- argument `previous_window_title` (type `String`)
### window_size
- emitted on `window size change`
- argument `update_coordinate` (type `String`, can be `X`, `Y` or `BOTH`)
- argument `window_size` (type `Vector2i`)
- argument `previous_window_size` (type `Vector2i`)
### window_pos
- emitted on `window position change`
- argument `update_coordinate` (type `String`, can be `X`, `Y` or `BOTH`)
- argument `window_pos` (type `Vector2i`)
- argument `previous_window_pos` (type `Vector2i`)
### logger_all
- emitted on `log output`
- argument `type` (type `String`, can be `"DIAG"`, `"INFO"`, `"WARN"` or `"ERROR"`)
- argument `script` (type `String`)
- argument `message` (type `String`)
### logger_diag
- emitted on `diagnostic log output`
- argument `script` (type `String`)
- argument `message` (type `String`)
### logger_info
- emitted on `informational log output`
- argument `script` (type `String`)
- argument `message` (type `String`)
### logger_warn
- emitted on `warning log output`
- argument `script` (type `String`)
- argument `message` (type `String`)
### logger_error
- emitted on `error log output`
- argument `script` (type `String`)
- argument `message` (type `String`)
## Internal variables
### window_title_prev
- type `String`
- default value `""`
- description `The previous title.`
### window_size_x_prev
- type `int`
- default value `0`
- description `The previous window size (x coordinate)`
### window_size_y_prev
- type `int`
- default value `0`
- description `The previous window size (y coordinate)`
### window_pos_x_prev
- type `int`
- default value `0`
- description `The previous window position (x coordinate)`
### window_pos_y_prev
- type `int`
- default value `0`
- description `The previous window position (y coordinate)`
## Internal functions
### _ready()
- returns `void`
- description `connects the logger's "logevent" signal with the "logger_update()" function`
### _process()
- returns `void`
- description `checks for window title, size and position changes and emits a signal if one changes`
- argument `_delta`
- type `float`
- mandatory `yes`
- description `The delta value passed by the engine`
### logger_update()
- returns `void`
- description `emits "logger_all" signal and checks against type and sends the corresponding "logger_<TYPE>" signal`
- argument `type`
- type `String`
- mandatory `yes`
- description `The log type`
- argument `script`
- type `String`
- mandatory `yes`
- description `The script responsible for the log output`
- argument `message`
- type `String`
- mandatory `yes`
- description `The log message`
- argument `_logmessage`
- type `String`
- mandatory `yes`
- description `The printed (processed) log message`

View file

@ -3,15 +3,15 @@ hide:
- navigation
---
# References index
Here you can find all code references.<br/>
**Index syntax**: *Human-friendly name (callable_gdscript.name)*
Welcome to the reference documentation! Here you can find everything you need to develop your game or application with CORE.
## [CORE configuration file (core.config)](/references/config.gd/)
## [CORE Holder (core)](/references/core.gd/)
## [Events (core.events)](/references/events.gd/)
## [Preprocessor (Preprocessor)](/references/preprocessor.gd/)
## [Resource Manager (core.resmgr)](/references/resmgr.gd/)
## [Scene Manager (core.smgr)](/references/smgr.gd/)
## [Splash Screen (core.splash)](/references/splash.gd/)
## [Window Manager (core.wmgr)](/references/wmgr.gd/)
## [Mother Of All Mods [Mod loader] (core.moam)](/references/moam.gd/)
## [The CORE configuration file](/references/Configuration_File/)
## [CORE](/references/CORE/)
## [Logger](/references/Logger/)
## [Preprocessor](/references/Preprocessor/)
## [Resource Manager](/references/ResourceManager/)
## [Scene Manager](/references/SceneManager/)
## [Splash Screen](/references/SplashScreen/)
## [Debug Display](/references/DebugDisplay/)
## [Miscellaneous](/references/Miscellaneous/)
## [Events](/references/Events/)

View file

@ -1,61 +0,0 @@
---
hide:
- navigation
---
# Mother Of All Mods [Modloader] (core.moam)
Loads and executes modifications.
## Methods
### load_mods()
- returns `Array`
- description `Loads all modifications and returns all encountered errors as a a collection of strings`
### load_mod()
- returns `String` (if **not** `""` some error occured)
- description `Loads and executes a modification`
- argument `mod_name`
- type `String`
- mandatory `yes`
- description `The modification name to use`
### unload_mods()
- returns `void`
- description `Unloads all loaded modifications`
### unload_mod()
- returns `void`
- description `Unloads a modification`
- argument `mod_name`
- type `String`
- mandatory `yes`
- description `The modification name to use`
### get_list()
- returns `Array`
- description `Returns a list of all loaded modification names`
### get_info()
- returns `Dictionary` (if a error occured the dict will contain a `error` key)
- description `Returns information about a modification`
- argument `mod_name`
- type `String`
- mandatory `yes`
- description `The modification name to use`
## Internal variables
Do not touch or you will cause breakage.
### modlist
- type `Array`
- default value `[]`
- description `All loaded modification (names)`
### config_loadpath
- type `String`
- default value `null`
- description `The mods directory all modifications are loaded from`
### config_wanted_name
- type `String`
- default value `null`
- description `Used for the modinfo filename. If set to "testapp" it will search for "testapp.coremod" files`
### config_wanted_version
- type `String`
- default value `null`
- description `The application or game version. Modifications will not load if they don't support the specified version`
### config_wanted_api
- type `String`
- default value `null`
- description `The application or game api version. Modifications will not load if they don't support the specified api version.`

View file

@ -1,219 +0,0 @@
---
hide:
- navigation
---
# Preprocessor (Preprocessor)
The **Preprocessor** can format text.
## Tags *(these can be used in log messages too!)*
All tags can be escaped by adding `esc_` before the tag name. Example:
```text
Raw: <esc_up><esc_np></esc_lo>
Output: <up><np></lo>
```
### No process `<np>`
- end tag `no`
- description `Disables preprocessing completely. Doesn't even display the prefix.`
- example:
``` text
Raw: <up>This is a</up><pa>test</pa><np> MESS<lo>age</lo>.
Output: <up>This is a</up><pa>test</pa> MESS<lo>age</lo>.
```
### Newline `<nl>`
- end tag `no`
- description `Makes a newline while respecting the prefix. Is much recommended over "\n".`
- example (with prefix `prefix_`):
``` text
Raw: Very nice message!<nl>Here's another message :)
Output:
prefix_Very nice message!
Here's another message :)
```
### Lowercase `<lo></lo>`
- end tag `yes`
- description `Makes your text lowercase.`
- example:
``` text
Raw: Did <lo>you FiNd THA</lo>T funny?
Output: Did you find thaT funny?
```
### Uppercase `<up></up>`
- end tag `yes`
- description `Makes your text uppercase.`
- example:
``` text
Raw: ThiS Te<up>XT should be UPPer</up>caSED
Output: ThiS TeXT SHOULD BE UPPERcaSED
```
### Camelcase `<ca></ca>`
- end tag `yes`
- description `Makes your text camelcase.`
- example:
``` text
Raw: This <ca>text should be CamelCa</ca>sed.
Output: This textShouldBeCamelCased.
```
### Pascalcase `<pa></pa>`
- end tag `yes`
- description `Makes your text pascalcase.`
- example:
``` text
Raw: This <pa>text should be PascelCa</pa>sed.
Output: This TextShouldBePascelCased.
```
### Snakecase `<sn></sn>`
- end tag `yes`
- description `Makes your text snakecase.`
- example:
``` text
Raw: This <sn>text should be SnakeCa</sn>sed.
Output: This text_should_be_snake_cased.
```
## Variables
### enabled
- type `bool`
- default value `true`
- description `Enables or disables the preprocessor.`
### verbose_logging
- type `bool`
- default value `false`
- description `Makes the log unreadable. Adds about twenty lines to every process() call.`
### tests_enabled
- type `bool`
- default value `true`
- description `Enables or disables preprocessor testing. Recommended to leave enabled as it disables the preprocessor if it's malfunctioning (somehow). Better to have unformatted text than broken text.`
### tests_level
- type `int`
- default value `1`
- description `Controls when test results are displayed. 0 = Never, 1 = On failure, 2 = Always`
## Methods
### do_tests()
- returns `void`
- description `Performs tests on all preprocessor functions. Very useful for catching bugs while debugging and/or modifying the preprocessor.`
- argument `ignore_flag`
- type `bool`
- mandatory `no, default value is false`
- description `ignores the "tests_enabled" variable if set to true`
### process()
- returns `String`
- description `Formats a message`
- argument `msg`
- type `String`
- mandatory `yes`
- description `The message used for processing`
- argument `prefix`
- type `String`
- mandatory `yes`
- description `The prefix used for newlines`
- argument `pre_msg`
- type `String`
- mandatory `no, default value is ""`
- description `Inserted before the message`
- argument `post_msg`
- type `String`
- mandatory `no, default value is ""`
- description `Inserted after the message`
- argument `exclusion_filter`
- type `Array`
- mandatory `no, default value is []`
- description `Removes specific Strings from the prefix (used in calculating spaces in _newline())`
## Internal variables
Do not touch these or you will cause breakage.
### tests_executed
- type `bool`
- default value `false`
- description `If tests have been executed already or not.`
### tests_log
- type `String`
- default value `""`
- description `The latest preprocessor testing log.`
### tests_success
- type `int`
- default value `0`
- description `The testing success count. If the value is 12, testing succeeded. If not, something is broken.`
## Internal Methods
Do not execute these or you will cause breakage.
### _ready()
- returns `void`
- description `Executes do_tests() and imports logger.`
### _newline()
- returns `String`
- description `Processes the <nl> tag`
- argument `msg`
- type `String`
- mandatory `yes`
- description `The message used for processing the tag`
- argument `prefix`
- type `String`
- mandatory `yes`
- description `The prefix used for newlines`
- argument `pre_msg`
- type `String`
- mandatory `yes`
- description `Inserted before the message`
- argument `post_msg`
- type `String`
- mandatory `yes`
- description `Inserted after the message`
- argument `exclusion_filter`
- type `Array`
- mandatory `yes`
- description `Removes specific Strings from the prefix (used in calculating spaces)`
### _case_lower()
- returns `String`
- description `Processes the <lo></lo> tags`
- argument `msg`
- type `String`
- mandatory `yes`
- description `The message used for processing the tags`
### _case_upper()
- returns `String`
- description `Processes the <up></up> tags`
- argument `msg`
- type `String`
- mandatory `yes`
- description `The message used for processing the tags`
### _case_camelcase()
- returns `String`
- description `Processes the <ca></ca> tags`
- argument `msg`
- type `String`
- mandatory `yes`
- description `The message used for processing the tags`
### _case_pascalcase()
- returns `String`
- description `Processes the <pa></pa> tags`
- argument `msg`
- type `String`
- mandatory `yes`
- description `The message used for processing the tags`
### _case_snakecase()
- returns `String`
- description `Processes the <sn></sn> tags`
- argument `msg`
- type `String`
- mandatory `yes`
- description `The message used for processing the tags`
### _case()
- returns `String`
- description `Executes all _case_* functions`
- argument `msg`
- type `String`
- mandatory `yes`
- description `The messages passed to all other _case_* functions`
### _escapes()
- returns `String`
- description `It escapes tags`
- argument `msg`
- type `String`
- mandatory `yes`
- description `The message used for processing the tags`
### _noprocess()
- returns `bool`
- description `Checks if the "msg" variable contains "<np>"`
- argument `msg`
- type `String`
- mandatory `yes`
- description `The message used for searching "<np>"`

View file

@ -1,137 +0,0 @@
---
hide:
- navigation
---
# Scene Manager (core.smgr)
Responsible for displaying scenes in order.
## Overlays
The scene manager uses something called **overlays**. They hold scenes while keeping order. You can think of them like organized collections of scenes *(because they are exactly that)*. There are four **configurable** and one **unconfigurable** overlay.
### Overlay #1 - `debug`
- description `The debug overlay should contain things like a FPS counter, debug menu, etc..`
- configurable `yes`
- more than one scene `yes`
- adding a scene **[add_debug()](#add_debug)**
- removing a scene **[remove_debug()](#remove_debug)**
### Overlay #2 - `cutscene`
- description `The cutscene should contain... well a cutscene.`
- configurable `yes`
- more than one scene `no`
- adding a scene **[add_cutscene()](#add_cutscene)**
- removing a scene **[remove_cutscene()](#remove_cutscene)**
### Overlay #3 - `menu`
- description `The menu overlay should contain multiple menu scenes.`
- configurable `yes`
- more than one scene `yes`
- adding a scene **[add_menu()](#add_menu)**
- removing a scene **[remove_menu()](#remove_menu)**
### Overlay #4 - `game`
- description `The game overlay should contain a game scene. We recommend displaying main menus under the game instead of the menu overlay.`
- configurable `yes`
- more than one scene `no`
- adding a scene **[add_game()](#add_game)**
- removing a scene **[remove_game()](#remove_game)**
### Overlay #5 - `COREBackground`
- description `COREBackground is a unconfigurable overlay responsible for displaying the log and serves as a background if nothing is displayed.`
- configurable `no`
- more than one scene `no`
## Methods
### add_debug()
- returns `bool`
- description `Adds a PackedScene to the debug overlay.`
- argument `resource_name`
- type `String`
- mandatory `yes`
- description `Used for loading the scene and the loaded scene name.`
### remove_debug()
- returns `bool`
- description `Removes a menu scene from the debug overlay.`
- argument `scene_name`
- type `String`
- mandatory `yes`
- description `Should be the same as the "resource_name" argument used previously in add_debug().`
### add_cutscene()
- returns `bool`
- description `Adds a PackedScene to the cutscene overlay.`
- argument `resource_name`
- type `String`
- mandatory `yes`
- description `Used for loading the scene and the loaded scene name.`
### remove_cutscene()
- returns `bool`
- description `Removes the game scene from the cutscene overlay.`
### add_menu()
- returns `bool`
- description `Adds a PackedScene to the menu overlay.`
- argument `resource_name`
- type `String`
- mandatory `yes`
- description `Used for loading the scene and the loaded scene name.`
### remove_menu()
- returns `bool`
- description `Removes a menu scene from the menu overlay.`
- argument `scene_name`
- type `String`
- mandatory `yes`
- description `Should be the same as the "resource_name" argument used previously in add_menu().`
### add_game()
- returns `bool`
- description `Adds a PackedScene to the game overlay.`
- argument `resource_name`
- type `String`
- mandatory `yes`
- description `Used for loading the scene and the loaded scene name.`
### remove_game()
- returns `bool`
- description `Removes the game scene from the game overlay.`
## Internal Variables
Do not touch or you will cause breakage.
### ccr
- type `Control`
- default value `null`
- description `The CORE Scene Root.`
### ccr_debug
- type `Control`
- default value `null`
- description `The debug overlay.`
### ccr_debug_names
- type `Array`
- default value `[]`
- description `A collection of all resource names loaded in the debug overlay.`
- Format `["resource_name"]`
### ccr_cutscene
- type `Control`
- default value `null`
- description `The cutscene overlay.`
### ccr_cutscene_inuse
- type `bool`
- default value `null`
- description `Used for checking if a cutscene scene has been loaded already.`
### ccr_menu
- type `Control`
- default value `null`
- description `The menu overlay.`
### ccr_menu_names
- type `Array`
- default value `[]`
- description `A collection of all resource names loaded in the menu overlay.`
- Format `["resource_name"]`
### ccr_game
- type `Control`
- default value `null`
- description `The game overlay.`
### ccr_game_inuse
- type `bool`
- default value `null`
- description `Used for checking if a game scene has been loaded already.`
## Internal methods
Do not execute these or you will cause breakage.
### _ready()
- returns `void`
- description `Adds the CORE Scene Root, migrates it and executes add_overlays()`
### add_overlays()
- returns `void`
- description `Adds all configurable overlays.`

View file

@ -1,45 +0,0 @@
---
hide:
- navigation
---
# Splash Screen (core.splash)
The splash screen component allows you to display a "loading screen" whilst hiding log output (COREBackground).
## Variables
### image
- type `String`
- default value `<splash_image config variable>`
- description `Path to a image, displayed in the center of the splash screen.`
### image_size
- type `float`
- default value `<splash_image_size config variable>`
- description `The size of your image. Used for both the x and y coordinates.`
### color
- type `String`
- default value `<splash_color config variable>`
- description `The background color.`
- format `AARRGGBB` or `RRGGBB` (`AA` = `alpha`, `RR` = `red`, `GG` = `green` and `BB` = `blue`)
## Methods
### apply_config()
- returns `void`
- description `Applies the variables "image", "image_size" and "color" to the scene.`
### display()
- returns `void`
- description `Makes the splash screen visible.`
### dissolve()
- returns `void`
- description `Makes the splash screen invisible.`
## Internal variables
Do not touch or you will cause breakage.
### enabled
- type `bool`
- default value `<splash_enabled config variable>
- description `If the splash screen module should be displayed at CORE startup or not.`
## Internal methods
Do not execute or you will cause breakage.
### _ready()
- returns `void`
- description `Executes apply_config() and executes display() if "enabled" is true.`

View file

@ -1,125 +0,0 @@
---
hide:
- navigation
---
# Window manager (core.wmgr)
Responsible for managing the main window.
## Modes
The window can be in one of five different modes. Those are:
### `WINDOWED`
A floating window.
### `MINIMIZED`
Minimizes the window to the taskbar/application list/etc..
### `MAXIMIZED`
Maximizes the window.
### `FULLSCREEN`
Hides all decorations and sets the window size to the screen size. Has multi-window support.
### `EXCLUSIVE_FULLSCREEN`
Same as the `FULLSCREEN` mode but has way less overhead at the cost of loosing multi-window support. Has different effects on different platforms:<br/>
**Windows**: *Depending on the video driver, the screen might black out for a few seconds.*<br/>
**macOS**: *Prevents the dock and menu from showing up when hovering over the edge of the screen.*<br/>
**Linux/BSD**: *Disables compositing (transparency effects, window close animation, etc.)*
## Methods
### set_size()
- returns `void`
- description `Updates the window size.`
- argument `x`
- type `int`
- mandatory `yes`
- description `The new window size (x coordinate).`
- argument `y`
- type `int`
- mandatory `yes`
- description `The new window size (y coordinate).`
### get_size()
- returns `Vector2i`
- description `Returns the window size.`
### set_position()
- returns `void`
- description `Updates the window position.`
- argument `x`
- type `int`
- mandatory `yes`
- description `The new window position (x coordinate).`
- argument `y`
- type `int`
- mandatory `yes`
- description `The new window position (y coordinate).`
### get_position()
- returns `Vector2i`
- description `Returns the window position.`
### set_title()
- returns `void`
- description `Updates the window title.`
- argument `title`
- type `String`
- mandatory `yes`
- description `The new window title.`
### get_title()
- returns `String`
- description `Returns the window title.`
### set_mode()
- returns `void`
- description `Updates the window mode.`
- argument `mode`
- type `String`
- mandatory `yes`
- description `The new window mode.`
- format follows `wmgr modes`
### get_mode()
- returns `String`
- description `Returns the window mode.`
### get_fps()
- returns `float`
- description `Returns the current framerate, also known as FPS or frames per second.`
- format `NUMBER.NUMBER` (if argument `flat` is `false`), `NUMBER` (if argument `flat` is `true`) or `INF` if the frame rate is infinite (can be caused if the physics fps is set too high, "should" never occur)
- argument `flat`
- type `bool`
- mandatory `no, default value is false`
- description `If decimal numbers should be returned or not.`
- format `If "true" decimal numbers will be removed, if "false" not.`
### get_rendertime()
- returns `float`
- description `Returns how long the last frame took to render (render time).`
### get_delta()
- returns `float`
- description `Returns the latest delta value.`
## Internal variables
Do not touch or you will cause breakage.
### window_size_x
- type `int`
- default value `<wmgr_size_x config variable>`
- description `The window size (x coordinate). Used at startup only.`
### window_size_y
- type `int`
- default value `<wmgr_size_y config variable>`
- description `The window size (y coordinate). Used at startup only.`
### window_title
- type `String`
- default value `<wmgr_title config variable>`
- description `The window title. Used at startup only.`
### window_mode
- type `String`
- default value `<wmgr_mode config variable>`
- description `The window mode. Used at startup only.`
- format follows `wmgr modes`
### delta
- type `float`
- default value `0`
- description `The latest delta value passed by the engine.`
## Internal methods
Do not execute or you will cause breakage.
### _ready()
- returns `void`
- description `Applies config variables.`
### _process()
- returns `void`
- description `Updates the "delta" variable.`
- argument `delta`
- type `float`
- mandatory `yes`
- description `You know what it is.`

View file

@ -5,42 +5,5 @@ hide:
# Troubleshooting CORE
**Warning:** This is a very messy document. Use the table of contents to get to your specified error. If you can't find your problem here, [create a issue](https://git.staropensource.de/staropensource/core/issues/new).
## Invalid argument issues
### (wmgr) [ERROR] Invalid window mode "`<PLACEHOLDER>`".
[wmgr's set_mode() function](/references/wmgr/#set_mode) recieved a invalid window mode. Only possible options are `"WINDOWED"`, `"MINIMIZED"`, `"MAXIMIZED"`, `"FULLSCREEN"` and `"EXCLUSIVE_FULLSCREEN"`.
### (smgr) [ERROR] Resource is not type of PackedScene
You tried loading something that's not a scene into the SceneTree. Check against what you are loading first!
## Common errors
### (smgr) [ERROR] Failed adding `<PLACEHOLDER>` scene: Only one `<PLACEHOLDER>` scene is allowed
Only one scene can be loaded into the `game` and `cutscene` overlays. Perform a check against the overlay first! [Click here for the smgr reference page](/references/smgr/)
### (smgr) [ERROR] Failed removing `<PLACEHOLDER>` scene: No `<PLACEHOLDER>` scene is active
You tried removing a scene in the `game` or `cutscene` overlay, but no scene is loaded in that overlay. Perform a check against the overlay first! [Click here for the smgr reference page](/references/smgr/)
### (smgr) [ERROR] Failed adding `<PLACEHOLDER>` scene: `<PLACEHOLDER>` scene with name "`<PLACEHOLDER>`" already exists
You tried loading a scene into the `menu` or `debug` overlay, but another scene with the same name already exists in that overlay. Perform a check against the overlay first! [Click here for the smgr reference page](/references/smgr/)
### (resmgr) [ERROR] Loading "`<PLACEHOLDER>`" failed: Resource is loaded already
You tried loading a resource with the resource manager, but a resource with the same name is loaded already. Perform a check against the resmgr first! [Click here for the resmgr reference page](/references/resmgr/)
### (resmgr) [ERROR] Unloading "`<PLACEHOLDER>`" failed: Resource is not present
You tried unloading a resource that is not loaded. Perform a check against the resmgr first! [Click for the resmgr reference page](/references/resmgr/)
### (resmgr) [ERROR] `<Unloading/Loading>` a batch failed: Batch is empty
The resource manager can't process a empty batch. Fill it with some information. [Click for the resmgr reference page](/references/resmgr/)
## Startup issues
### coreinit -> CORE only supports Godot `<PLACEHOLDER>`. Please upgrade/downgrade your Godot Project to `<PLACEHOLDER>`.
Update or downgrade your Godot version to one that CORE supports. See the [requirements page](/requirements/) for more information.
### coreinit -> The CORE logger is missing in your autoload project settings!
The CORE logger (found at `res://CORE/logger.gd`) is missing from your autoload list. Just add it under the name `Logger` and make sure to check `Global variable`.
### coreinit -> The CORE preprocessor is missing in your autoload project settings!
The CORE preprocessor (found at `res://CORE/preprocessor.gd`) is missing from your autoload list. Just add it under the name `Preprocessor` and make sure to check `Global variable`.
### coreinit -> The CORE configuration file (config.gd) is missing! Please copy the config.gd.example file and rename it to config.gd!
The CORE configuration file is missing. Just copy `config.gd.example` and rename it to `config.gd`. Make sure to update it to your likings.
### coreloader.gd:46 @ _ready(): Resource file not found: res://.
The variable `core_startupscript` in CORE's `config.gd` file is empty or points to a missing script. Either set the variable or create a new initialization script.
## Impossible errors
**If you somehow encounter one of these errors, [report them immediately please](https://git.staropensource.de/staropensource/core/issues/new).**
### Failed attaching `<PLACEHOLDER>` to CORE: Invalid component
Failed attaching a CORE component (for example `resmgr`) to the CORE holder (`core.gd`).
### Failed to get window mode: The window mode id "`<PLACEHOLDER`>" is not known to CORE.
Godot reported a window mode that CORE can't handle. Can be caused if the version check is removed and a higher Godot version is used than CORE supports.
## Work In Progress
This page will be documented soon. Just shoot [a mail](mailto:support@staropensource.de) or [a private message](https://net.staropensource.de/@soscore) at us for now.

View file

@ -6,5 +6,3 @@ hide:
Updating CORE is the same process as installing it. Just click on `Update` instead of `Install` in the **CORE Manager**.
### [Click to visit the installation page](/install/)
<small>Note for contributers: If the update process changes in the future we just need to update the documentation page instead of the whole documentation.</small>

115
events.gd
View file

@ -1,19 +1,28 @@
# events.gd
# Events
#
# This file is part of StarOpenSource CORE (SOSCORE)
# Made by the StarOpenSource Project and Contributers
# Licensed under GNU GPLv3
######################################
# 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) #
######################################
extends Node
@onready
var core = get_node(NodePath("/root/core"))
var window_title_prev = ""
var window_size_x_prev = 0
var window_size_y_prev = 0
var window_pos_x_prev = 0
var window_pos_y_prev = 0
# CORE modules
var core: Node = null
var logger: Node = null
# Used for checking if any values have changed
var prev_window_title: String = ""
var prev_window_size_x: int = 0
var prev_window_size_y: int = 0
var prev_window_pos_x: int = 0
var prev_window_pos_y: int = 0
# Event signals
signal window_title
signal window_size
signal window_pos
@ -23,52 +32,64 @@ signal logger_info
signal logger_warn
signal logger_error
# Set up connection between logger's logevent and logger_update()
func initialize() -> void:
if core.protection_mode: return
Logger.connect("logevent",Callable(self,"logger_update"))
core.setready()
func _process(_delta:float) -> void:
if core.protection_mode: return
var window_title_var = core.wmgr.get_title()
var window_size_x = core.wmgr.get_size().x
var window_size_y = core.wmgr.get_size().y
var window_pos_x = core.wmgr.get_position().x
var window_pos_y = core.wmgr.get_position().y
if window_title_prev != window_title_var:
emit_signal("window_title",window_title_var,window_title_prev)
window_title_prev = window_title_var
if window_size_x != window_size_x_prev and window_size_y != window_size_y_prev:
emit_signal("window_size","BOTH",Vector2i(window_size_x,window_size_y),Vector2i(window_size_x_prev,window_size_y_prev))
window_size_x_prev = window_size_x
window_size_y_prev = window_size_y
elif window_size_x != window_size_x_prev:
emit_signal("window_size","X",Vector2i(window_size_x,window_size_y),Vector2i(window_size_x_prev,window_size_y_prev))
window_size_x_prev = window_size_x
elif window_size_y != window_size_y_prev:
emit_signal("window_size","Y",Vector2i(window_size_x,window_size_y),Vector2i(window_size_x_prev,window_size_y_prev))
window_size_y_prev = window_size_y
if window_pos_x != window_pos_x_prev and window_pos_y != window_pos_y_prev:
emit_signal("window_pos","BOTH",Vector2i(window_pos_x,window_pos_y),Vector2i(window_pos_x_prev,window_pos_y_prev))
window_pos_x_prev = window_pos_x
window_pos_y_prev = window_pos_y
elif window_pos_x != window_pos_x_prev:
emit_signal("window_pos","X",Vector2i(window_pos_x,window_pos_y),Vector2i(window_pos_x_prev,window_pos_y_prev))
window_pos_x_prev = window_pos_x
elif window_pos_y != window_pos_y_prev:
emit_signal("window_pos","Y",Vector2i(window_pos_x,window_pos_y),Vector2i(window_pos_x_prev,window_pos_y_prev))
window_pos_y_prev = window_pos_y
# logevent (signal) -> logger_update()
logger.connect("logevent",Callable(self,"logger_update"))
func logger_update(type:String,script:String,message:String,_logmessage:String) -> void:
if core.protection_mode: return
# Emit signal logger_all for all log messages
emit_signal("logger_all",type,script,message)
# Check for log type and emit the right signal
if type == "DIAG":
emit_signal("logger_diag",script,message)
elif type == "INFO":
emit_signal("logger_info",script,message)
elif type == "WARN":
emit_signal("logger_warn",script,message)
elif type == "ERROR":
elif type == "ERR!":
emit_signal("logger_error",script,message)
else:
core.exception("events","The log type \"" + type + "\" is not known to events.gd")
# Check various variables and emit signals if they changed
func _process(_delta:float) -> void:
process_window_title()
process_window_size()
process_window_pos()
func process_window_title() -> void:
var new_window_title: String = get_tree().root.title
if prev_window_title != new_window_title:
emit_signal("window_title",new_window_title,prev_window_title)
prev_window_title = new_window_title
func process_window_size() -> void:
var new_window_size_x: int = DisplayServer.window_get_size().x
var new_window_size_y: int = DisplayServer.window_get_size().y
if new_window_size_x != prev_window_size_x and new_window_size_y != prev_window_size_y:
emit_signal("window_size","BOTH",Vector2i(new_window_size_x,new_window_size_y),Vector2i(prev_window_size_x,prev_window_size_y))
prev_window_size_x = new_window_size_x
prev_window_size_y = new_window_size_y
elif new_window_size_x != prev_window_size_x:
emit_signal("window_size","X",Vector2i(new_window_size_x,new_window_size_y),Vector2i(prev_window_size_x,prev_window_size_y))
prev_window_size_x = new_window_size_x
elif new_window_size_y != prev_window_size_y:
emit_signal("window_size","Y",Vector2i(new_window_size_x,new_window_size_y),Vector2i(prev_window_size_x,prev_window_size_y))
prev_window_size_y = new_window_size_y
func process_window_pos() -> void:
var new_window_pos_x: int = DisplayServer.window_get_position().x
var new_window_pos_y: int = DisplayServer.window_get_position().y
if new_window_pos_x != prev_window_pos_x and new_window_pos_y != prev_window_pos_y:
emit_signal("window_pos","BOTH",Vector2i(new_window_pos_x,new_window_pos_y),Vector2i(prev_window_pos_x,prev_window_pos_y))
prev_window_pos_x = new_window_pos_x
prev_window_pos_y = new_window_pos_y
elif new_window_pos_x != prev_window_pos_x:
emit_signal("window_pos","X",Vector2i(new_window_pos_x,new_window_pos_y),Vector2i(prev_window_pos_x,prev_window_pos_y))
prev_window_pos_x = new_window_pos_x
elif new_window_pos_y != prev_window_pos_y:
emit_signal("window_pos","Y",Vector2i(new_window_pos_x,new_window_pos_y),Vector2i(prev_window_pos_x,prev_window_pos_y))
prev_window_pos_y = new_window_pos_y

143
logger.gd
View file

@ -1,73 +1,118 @@
# logger.gd
# CORE Logger
#
# This file is part of StarOpenSource CORE (SOSCORE)
# Made by the StarOpenSource Project and Contributers
# Licensed under GNU GPLv3
extends Control
######################################
# 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) #
######################################
extends Node
# CORE modules
var core: Node = null
var preprocessor: Node = null
# Enables/disables the logger
var enabled: bool = true
# Enables/disables diagnostic log messages
var diagnostic: bool = false
# Signals
signal logevent
@onready
var preprocessor = get_node(NodePath("/root/Preprocessor"))
@export
@export_category("Configuration")
# Enables/disables logging
var enable = true
@export
@export_category("Configuration")
# Enables/disables diagnostic/verbose logging
var enable_diag = false
func initialize() -> void:
if core.protection_mode: return
if preprocessor == null:
return
diag("CORE/logger.gd","Logger is ready.")
# Initializes the
func _ready() -> void:
print("logger -> Initializing Logger")
if get_node_or_null(NodePath("/root/Preprocessor")) == null:
print("logger -> Preprocessor is not loaded. Shutting application down...")
get_tree().quit(1)
await get_tree().create_timer(1).timeout
diag("Logger","Logger is ready.")
func diag(script:String,message:String,preproc:bool = false) -> void:
if enable and enable_diag:
if preproc and Preprocessor.enabled:
var logmsg = preprocessor.process(message,"[color=gray](" + script + ") [DIAG] [/color]","[color=gray][b]","[/b][/color]",["[color=gray]","[/color]"])
func diag(script:String,message:String,preproc:bool = true) -> void:
if core.protection_mode: return
# Check if both the logger and diagnostic log messages are enabled
if enabled and diagnostic:
# Check if preprocessing is allowed for this message and if the preprocessor is enabled
if preproc and preprocessor.enabled:
# Run the message through the preprocessor if enabled/allowed
var logmsg: String = preprocessor.process(message,"[color=gray](" + script + ") [DIAG] [/color]","[color=gray][b]","[/b][/color]",["[color=gray]","[/color]"])
# Print the message
print_rich(logmsg)
# Emit logevent signal
emit_signal("logevent","DIAG",script,message,logmsg)
else:
var logmsg = "[color=gray](" + script + ") [DIAG] [b]" + message + "[/b][/color]"
print_rich(logmsg)
# Construct a log message normally if preprocessor is disabled/disallowed
# Note: We do not include bold and color tags in here because they can mess
# up the log messages in some cases
var logmsg: String = "(" + script + ") [DIAG] " + message
# Print the message
print(logmsg)
# Emit logevent signal
emit_signal("logevent","DIAG",script,message,logmsg)
func info(script:String,message:String,preproc:bool = true) -> void:
if enable:
if preproc and Preprocessor.enabled:
var logmsg = preprocessor.process(message,"[color=white](" + script + ") [INFO] [/color]","[color=white][b]","[/b][/color]",["[color=white]","[/color]"])
if core.protection_mode: return
# Check if the logger is enabled
if enabled:
# Check if preprocessing is allowed for this message and if the preprocessor is enabled
if preproc and preprocessor.enabled:
# Run the message through the preprocessor if enabled/allowed
var logmsg: String = preprocessor.process(message,"[color=white](" + script + ") [INFO] [/color]","[color=white][b]","[/b][/color]",["[color=white]","[/color]"])
# Print the message
print_rich(logmsg)
# Emit logevent signal
emit_signal("logevent","INFO",script,message,logmsg)
else:
var logmsg = "(" + script + ") [INFO] [b]" + message + "[/b]"
print_rich(logmsg)
# Construct a log message normally if preprocessor is disabled/disallowed
# Note: We do not include bold and color tags in here because they can mess
# up the log messages in some cases
var logmsg: String = "(" + script + ") [INFO] " + message
# Print the message
print(logmsg)
# Emit logevent signal
emit_signal("logevent","INFO",script,message,logmsg)
func warn(script:String,message:String,preproc:bool = true) -> void:
if enable:
if preproc and Preprocessor.enabled:
var logmsg = preprocessor.process(message,"[color=orange](" + script + ") [WARN] [/color]","[color=orange][b]","[/b][/color]",["[color=orange]","[/color]"])
if core.protection_mode: return
# Check if the logger is enabled
if enabled:
# Check if preprocessing is allowed for this message and if the preprocessor is enabled
if preproc and preprocessor.enabled:
# Run the message through the preprocessor if enabled/allowed
var logmsg: String = preprocessor.process(message,"[color=orange](" + script + ") [WARN] [/color]","[color=orange][b]","[/b][/color]",["[color=orange]","[/color]"])
# Print the message
print_rich(logmsg)
# Emit logevent signal
emit_signal("logevent","WARN",script,message,logmsg)
else:
var logmsg = "[color=orange](" + script + ") [WARN] [b]" + message + "[/b][/color]"
print_rich(logmsg)
# Construct a log message normally if preprocessor is disabled/disallowed
# Note: We do not include bold and color tags in here because they can mess
# up the log messages in some cases
var logmsg: String = "(" + script + ") [WARN] " + message
# Print the message
print(logmsg)
# Emit logevent signal
emit_signal("logevent","WARN",script,message,logmsg)
func error(script:String,message:String,preproc:bool = true) -> void:
if enable:
if preproc and Preprocessor.enabled:
var logmsg = preprocessor.process(message,"[color=red](" + script + ") [ERROR] [/color]","[color=red][b]","[/b][/color]",["[color=red]","[/color]"])
if core.protection_mode: return
# Check if the logger is enabled
if enabled:
# Check if preprocessing is allowed for this message and if the preprocessor is enabled
if preproc and preprocessor.enabled:
# Run the message through the preprocessor if enabled/allowed
var logmsg: String = preprocessor.process(message,"[color=red](" + script + ") [ERR!] [/color]","[color=red][b]","[/b][/color]",["[color=red]","[/color]"])
# Print the message
print_rich(logmsg)
emit_signal("logevent","ERROR",script,message,logmsg)
# Emit logevent signal
emit_signal("logevent","ERR!",script,message,logmsg)
else:
var logmsg = "[color=red](" + script + ") [ERROR] [b]" + message + "[/b][/color]"
print_rich(logmsg)
emit_signal("logevent","ERROR",script,message,logmsg)
# Construct a log message normally if preprocessor is disabled/disallowed
# Note: We do not include bold and color tags in here because they can mess
# up the log messages in some cases
var logmsg: String = "(" + script + ") [ERR!] " + message
# Print the message
print(logmsg)
# Emit logevent signal
emit_signal("logevent","ERR!",script,message,logmsg)

68
misc.gd Normal file
View file

@ -0,0 +1,68 @@
######################################
# 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) #
######################################
extends Node
# CORE modules
var core: Node = null
# Delta value, used for get_fps() and get_delta()
var delta: float = 0.0
# Updates delta variable
func _process(delta_process) -> void:
delta = delta_process
# Returns the title of the main window
## Included as DisplayServer.window_get_title() (for some
## reason) does not exist and not many know that /root/
## is a Window node (which does have a "title" variable)
func get_title() -> String:
if core.protection_mode: return ""
return get_tree().root.title
# Returns the current FPS (Frames Per Second) value
func get_fps(flatten:bool = false) -> float:
if core.protection_mode: return 0.0
if str(delta) == "0":
# In the rare case where delta is zero, return INF
return INF
else:
if flatten:
# Removes decimal numbers
return float(int(1/delta))
else:
# Yes, it's weird but 1/delta does return the FPS value.
return 1/delta
# Returns the time it took Godot to render a frame
func get_rendertime() -> float:
if core.protection_mode: return 0.0
return Performance.get_monitor(Performance.TIME_PROCESS)
# Returns the delta time
func get_delta() -> float:
if core.protection_mode: return 0.0
return delta
# Converts a number of bytes to a number of mebibytes
func byte_to_mib(bytes:int,flatten:bool = true) -> float:
if flatten:
@warning_ignore("integer_division")
return bytes/1048576
return bytes/float(1048576)
# Flattens a floating point number
func flat_float(number:float) -> float:
return float(int(number))
func flat_float_int(number:float) -> int:
return int(number)

View file

@ -21,7 +21,8 @@ nav:
- Home: index.md
- Licensing: licensing.md
- Installing: install.md
- Updating: update.md
- Quick Start Guide: quickstartguide.md
- Breaking commits: breaking-commits.md
- Troubleshooting: troubleshooting.md
- References: references/
- Source code: https://git.staropensource.de/staropensource/core/

View file

@ -1,13 +1,27 @@
######################################
# 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) #
######################################
extends Node
@onready
var core = get_node("/root/core")
var fsizes = {"text":"16","h1":"29","h2":"24","h3":"19","h4":"14","h5":"9","h6":"4"}
# CORE modules
var core: Node = null
var logger: Node = null
# Font sizes
var fsizes: Dictionary = {"text":"16","h1":"29","h2":"24","h3":"19","h4":"14","h5":"9","h6":"4"}
func parse(content:String) -> String:
var parse_text = ""
var parse_text: String = ""
for line in content.split("\n",false):
var line_mod = line
var line_mod: String = line
if line_mod.begins_with("######"):
line_mod = line_mod.replace("######","[font_size=" + fsizes["h6"] + "]") + "[/font_size]"
elif line_mod.begins_with("#####"):
@ -24,6 +38,3 @@ func parse(content:String) -> String:
line_mod = "[font_size=" + fsizes["text"] + "]" + line_mod + "[/font_size]"
parse_text = parse_text + line_mod + "\n"
return parse_text
func initialize() -> void:
core.setready()

View file

@ -1,193 +1,60 @@
# preprocessor.gd
# CORE Text Preprocessor
#
# This file is part of StarOpenSource CORE (SOSCORE)
# Made by the StarOpenSource Project and Contributers
# Licensed under GNU GPLv3
#
# <tag> list/table:
# Tag | Description
# <nl> | Newline (DO NOT USE '\n'!)
# <lo> | Text is lowercase until closing tag
# <up> | Text is UPPERCASE until closing tag
# <ca> | Text is camelCase until closing tag
# <pa> | Text is PascalCase until closing tag
# <sn> | Text is snake_case until closing tag
# </lo> | Closing tag for <lo>
# </up> | Closing tag for <up>
# </ca> | Closing tag for <ca>
# </pa> | Closing tag for <pa>
# </sn> | Closing tag for <sn>
######################################
# 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) #
######################################
extends Node
extends Control
## ## # ##### ##### ####
## # # # # # # #
## # # # # # # ####
## # ## # # # #
## # # ##### # ####
## The preprocessor is *very* undocumented at this point
## in time as it is a little bit complicated. We may document
## it in the future, but for now you have to read the source.
##
## - JeremyStarTM
var logger = null
@export_category("Configuration")
# Enables/disables Preprocessor.
# CORE modules
var core: Node = null
var logger: Node = null
# Enables/disables preprocessor functionality
@export var enabled = true
# Enables/disables verbose preprocessing. DO NOT ENABLE. VERBOSE PREPROCESSING ADDS 20 LINES FOR EACH LOGGER CALL WITH PREPROCESSING ENABLED AND MAKES THE LOG UNREADABLE. ONLY ENABLE IF YOU KNOW WHAT YOU ARE DOING.
# Requires Logger.enable -> true
@export var verbose_logging = false
# Enables/disables Preprocessor tests. Please do not disable as testing the preprocessor can help catch bugs early.
# Requires enabled -> true
@export var tests_enabled = true
# Controls how test results are displayed
# 0 = Never show results
# 1 = Only display on failure
# 2 = Always display
@export var tests_level = 1
var tests_executed = false
var tests_log = ""
var tests_success = 0
# Do not enable unless you exactly know what you are doing!
# It will spam your log chock full of useless garbage!
@export var diagnostic = false
func _ready() -> void:
print("preprocessor -> Initializing Preprocessor")
print("preprocessor -> Delaying initialization by 0.75s")
await get_tree().create_timer(0.75).timeout
logger = get_node(NodePath("/root/Logger"))
await get_tree().create_timer(0.05).timeout
do_tests(false)
if enabled:
logger.diag("Preprocessor","Preprocessor ready.",false)
else:
logger.diag("Preprocessor","Preprocessor disabled.",false)
# Performs tests on all Preprocessor features to help catch bugs while debugging.
# Recommended to leave enabled because log output might look weird if the a faulty commit is installed.
# Use tests_executed to check if the tests have been executed, use tests_log for the test log and
# read tests_success if you want the number of successful tests.
func do_tests(ignore_flag:bool = false) -> void:
logger.diag("Preprocessor","Testing preprocessor...",false)
# If tests are disaled and ignore_flag is false return
if !tests_enabled and !ignore_flag:
logger.diag("Preprocessor","Testing failed: Tests are disabled.",false)
# Checks if logger is null
func initialize() -> void:
if core.protection_mode: return
if logger == null:
return
# If the Preprocessor is not enabled return
if !enabled:
logger.diag("Preprocessor","Testing failed: Preprocessor is disabled.",false)
return
# Expected test resulsts
var tests_newlines = "test_prefix_Line 1.\n _Line 2.\n _Line 3."
var tests_uppercase = "a THIS TEXT SHOULD BE UPPPERCASED b"
var tests_lowercase = "a this text should be lowercased b"
var tests_camelcase = "a thisShouldBeCamelCasEd b"
var tests_pascalcase = "a ThisShouldBePascalCasEd b"
var tests_snakecase = "a this_should_be_snake_cas_ed b"
var tests_escapes_newlines = "<nl>"
var tests_escapes_uppercase = "<up></up>"
var tests_escapes_lowercase = "<lo></lo>"
var tests_escapes_camelcase = "<ca></ca>"
var tests_escapes_pascalcase = "<pa></pa>"
var tests_escapes_snakecase = "<sn></sn>"
# Actual tests performed using pre()
var tests_newlines_result = process("Line 1<nl>Line 2<nl>Line 3","test_prefix","_",".")
var tests_uppercase_result = process("a <up>ThIs tExT sHoUlD bE uPpPeRcAsEd</up> b")
var tests_lowercase_result = process("a <lo>ThIs tExT sHoUlD bE lOwErCaSeD</lo> b")
var tests_camelcase_result = process("a <ca>thisShould_be_camel_CASEd</ca> b")
var tests_pascalcase_result = process("a <pa>thisShould_be_pascal_CASEd</pa> b")
var tests_snakecase_result = process("a <sn>thisShould_be_snake_CASEd</sn> b")
var tests_escapes_newlines_result = process("<esc_nl>")
var tests_escapes_uppercase_result = process("<esc_up></esc_up>")
var tests_escapes_lowercase_result = process("<esc_lo></esc_lo>")
var tests_escapes_camelcase_result = process("<esc_ca></esc_ca>")
var tests_escapes_pascalcase_result = process("<esc_pa></esc_pa>")
var tests_escapes_snakecase_result = process("<esc_sn></esc_sn>")
# Test success and log
tests_success = 0
tests_log = ""
# Checks if all tests are equal to their expected results and logs the result.
if tests_newlines_result == tests_newlines:
tests_success = tests_success+1
tests_log = "Y Test NEWLINES returned:\n" + tests_newlines_result + "\n"
else:
tests_log = "N Test NEWLINES returned:\n" + tests_newlines_result + "\n... instead of:\n" + tests_newlines + "\n"
if tests_uppercase_result == tests_uppercase:
tests_success = tests_success+1
tests_log = tests_log + "Y Test UPPERCASE returned \"" + tests_uppercase_result + "\".\n"
else:
tests_log = tests_log + "N Test UPPERCASE returned \"" + tests_uppercase_result + "\" instead of \"" + tests_uppercase + "\".\n"
if tests_lowercase_result == tests_lowercase:
tests_success = tests_success+1
tests_log = tests_log + "Y Test LOWERCASE returned \"" + tests_lowercase_result + "\".\n"
else:
tests_log = tests_log + "N Test LOWERCASE returned \"" + tests_lowercase_result + "\" instead of \"" + tests_lowercase + "\".\n"
if tests_camelcase_result == tests_camelcase:
tests_success = tests_success+1
tests_log = tests_log + "Y Test CAMELCASE returned \"" + tests_camelcase_result + "\".\n"
else:
tests_log = tests_log + "N Test CAMELCASE returned \"" + tests_camelcase_result + "\" instead of \"" + tests_camelcase + "\".\n"
if tests_pascalcase_result == tests_pascalcase:
tests_success = tests_success+1
tests_log = tests_log + "Y Test PASCALCASE returned \"" + tests_pascalcase_result + "\".\n"
else:
tests_log = tests_log + "N Test PASCALCASE returned \"" + tests_pascalcase_result + "\" instead of \"" + tests_pascalcase + "\".\n"
if tests_snakecase_result == tests_snakecase:
tests_success = tests_success+1
tests_log = tests_log + "Y Test SNAKECASE returned \"" + tests_snakecase_result + "\".\n"
else:
tests_log = tests_log + "N Test SNAKECASE returned \"" + tests_snakecase_result + "\" instead of \"" + tests_snakecase + "\".\n"
if tests_escapes_newlines_result == tests_escapes_newlines:
tests_success = tests_success+1
tests_log = tests_log + "Y Test ESCAPES_NEWLINES returned \"" + tests_escapes_newlines_result + "\".\n"
else:
tests_log = tests_log + "N Test ESCAPES_NEWLINES returned \"" + tests_escapes_newlines_result + "\" instead of \"" + tests_escapes_newlines + "\".\n"
if tests_escapes_uppercase_result == tests_escapes_uppercase:
tests_success = tests_success+1
tests_log = tests_log + "Y Test ESCAPES_UPPERCASE returned \"" + tests_escapes_uppercase_result + "\".\n"
else:
tests_log = tests_log + "N Test ESCAPES_UPPERCASE returned \"" + tests_escapes_uppercase_result + "\" instead of \"" + tests_escapes_uppercase + "\".\n"
if tests_escapes_lowercase_result == tests_escapes_lowercase:
tests_success = tests_success+1
tests_log = tests_log + "Y Test ESCAPES_LOWERCASE returned \"" + tests_escapes_lowercase_result + "\".\n"
else:
tests_log = tests_log + "N Test ESCAPES_LOWERCASE returned \"" + tests_escapes_lowercase_result + "\" instead of \"" + tests_escapes_lowercase + "\".\n"
if tests_escapes_camelcase_result == tests_escapes_camelcase:
tests_success = tests_success+1
tests_log = tests_log + "Y Test ESCAPES_CAMELCASE returned \"" + tests_escapes_camelcase_result + "\".\n"
else:
tests_log = tests_log + "N Test ESCAPES_CAMELCASE returned \"" + tests_escapes_camelcase_result + "\" instead of \"" + tests_escapes_camelcase + "\".\n"
if tests_escapes_pascalcase_result == tests_escapes_pascalcase:
tests_success = tests_success+1
tests_log = tests_log + "Y Test ESCAPES_PASCALCASE returned \"" + tests_escapes_pascalcase_result + "\".\n"
else:
tests_log = tests_log + "N Test ESCAPES_PASCALCASE returned \"" + tests_escapes_pascalcase_result + "\" instead of \"" + tests_escapes_pascalcase + "\".\n"
if tests_escapes_snakecase_result == tests_escapes_snakecase:
tests_success = tests_success+1
tests_log = tests_log + "Y Test ESCAPES_SNAKECASE returned \"" + tests_escapes_snakecase_result + "\".\n"
else:
tests_log = tests_log + "N Test ESCAPES_SNAKECASE returned \"" + tests_escapes_snakecase_result + "\" instead of \"." + tests_escapes_snakecase + "\".\n"
tests_log = tests_log.left(tests_log.length()-1) # Removes unnecessary line.
tests_executed = true
# Checks if all tests were successful. If not disable the Preprocessor and print log.
if tests_success == 12:
enabled = true
logger.diag("Preprocessor","Testing complete: All preprocessor features are working as intended.",false)
if tests_level == 2:
logger.diag("Preprocessor","Log:\n" + tests_log)
else:
enabled = false
logger.error("Preprocessor","Testing failed: Preprocessor is malfunctioning and is now disabled.",false)
if tests_level >= 1:
logger.error("Preprocessor","Log:\n" + tests_log)
logger.diag("CORE/preprocessor.gd","Preprocessor is ready.",false)
# Processes <nl> tags
# Parses <nl> tags
func _newline(msg:String,prefix:String,pre_msg:String,post_msg:String,exclusion_filter:Array) -> String:
if verbose_logging:
logger.diag("Preprocessor","Preprocessing newlines")
if core.protection_mode: return ""
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing newline tags",false)
var prefix_space = prefix
for exclusion in exclusion_filter:
prefix_space = prefix_space.replace(exclusion,"")
prefix_space = " ".repeat(prefix_space.length())
var msg_proc = prefix + pre_msg + msg.replace("<nl>",post_msg + "\n" + prefix_space + pre_msg) + post_msg
if verbose_logging:
logger.diag("Preprocessor","Preprocessed newlines")
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed newline tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
return msg_proc
# Processes <lo> and </lo> tags
# Warning: Please do NOT modify the while true loop. It was a pain to debug, believe me.
# Parses <lo> and </lo> tags
func _case_lower(msg:String) -> String:
if verbose_logging:
logger.diag("Preprocessor","Preprocessing lowercasing")
if core.protection_mode: return ""
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing lowercase tags",false)
var msg_proc = msg
while true:
var index_one = msg_proc.find("<lo>")
@ -198,20 +65,18 @@ func _case_lower(msg:String) -> String:
var index_proc = msg_proc.substr(index_one,index_two)
msg_proc = msg_proc.replace(index_proc,index_proc.replace("<lo>","").replace("</lo>","").to_lower())
else:
logger.error("Preprocessor","Failed preprocessing message \"" + msg + "\" (stage LOWERCASE).",false)
core.exception("Preprocessor","Failed parsing lowercase tags in message \"" + msg + "\" (missing end tag?)")
msg_proc = msg
break
else:
break
if verbose_logging:
logger.diag("Preprocessor","Preprocessed lowercasing")
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed lowercase tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
return msg_proc
# Processes <up> and </up> tags
# Warning: Please do NOT modify the while true loop. It was a pain to debug, believe me.
# Parses <up> and </up> tags
func _case_upper(msg:String) -> String:
if verbose_logging:
logger.diag("Preprocessor","Preprocessing uppercasing")
if core.protection_mode: return ""
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing uppercase tags",false)
var msg_proc = msg
while true:
var index_one = msg_proc.find("<up>")
@ -222,20 +87,18 @@ func _case_upper(msg:String) -> String:
var index_proc = msg_proc.substr(index_one,index_two)
msg_proc = msg_proc.replace(index_proc,index_proc.replace("<up>","").replace("</up>","").to_upper())
else:
logger.error("Preprocessor","Failed preprocessing message \"" + msg + "\". (stage UPPERCASE).",false)
core.exception("Preprocessor","Failed parsing uppercase tags in message \"" + msg + "\" (missing end tag?)")
msg_proc = msg
break
else:
break
if verbose_logging:
logger.diag("Preprocessor","Preprocessed uppercasing")
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed uppercase tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
return msg_proc
# Processes <ca> and </ca> tags
# Warning: Please do NOT modify the while true loop. It was a pain to debug, believe me.
# Parses <ca> and </ca> tags
func _case_camelcase(msg:String) -> String:
if verbose_logging:
logger.diag("Preprocessor","Preprocessing camelcasing")
if core.protection_mode: return ""
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing camelcase tags",false)
var msg_proc = msg
while true:
var index_one = msg_proc.find("<ca>")
@ -246,20 +109,18 @@ func _case_camelcase(msg:String) -> String:
var index_proc = msg_proc.substr(index_one,index_two)
msg_proc = msg_proc.replace(index_proc,index_proc.replace("<ca>","").replace("</ca>","").to_camel_case())
else:
logger.error("Preprocessor","Failed preprocessing message \"" + msg + "\". (stage CAMELCASE).",false)
core.exception("Preprocessor","Failed parsing camelcase tags in message \"" + msg + "\" (missing end tag?)")
msg_proc = msg
break
else:
break
if verbose_logging:
logger.diag("Preprocessor","Preprocessed camelcasing")
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed camelcase tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
return msg_proc
# Processes <pa> and </pa> tags
# Warning: Please do NOT modify the while true loop. It was a pain to debug, believe me.
# Parses <pa> and </pa> tags
func _case_pascalcase(msg:String) -> String:
if verbose_logging:
logger.diag("Preprocessor","Preprocessing pascalcasing")
if core.protection_mode: return ""
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing pascalcase tags",false)
var msg_proc = msg
while true:
var index_one = msg_proc.find("<pa>")
@ -270,20 +131,18 @@ func _case_pascalcase(msg:String) -> String:
var index_proc = msg_proc.substr(index_one,index_two)
msg_proc = msg_proc.replace(index_proc,index_proc.replace("<pa>","").replace("</pa>","").to_pascal_case())
else:
logger.error("Preprocessor","Failed preprocessing message \"" + msg + "\". (stage PASCALCASE).",false)
core.exception("Preprocessor","Failed parsing pascalcase tags in message \"" + msg + "\" (missing end tag?)")
msg_proc = msg
break
else:
break
if verbose_logging:
logger.diag("Preprocessor","Preprocessed pascalcasing")
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed pascalcase tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
return msg_proc
# Processes <sn> and </sn> tags
# Warning: Please do NOT modify the while true loop. It was a pain to debug, believe me.
# Parses <sn> and </sn> tags
func _case_snakecase(msg:String) -> String:
if verbose_logging:
logger.diag("Preprocessor","Preprocessing snakecasing")
if core.protection_mode: return ""
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing snakecase tags",false)
var msg_proc = msg
while true:
var index_one = msg_proc.find("<sn>")
@ -294,32 +153,30 @@ func _case_snakecase(msg:String) -> String:
var index_proc = msg_proc.substr(index_one,index_two)
msg_proc = msg_proc.replace(index_proc,index_proc.replace("<sn>","").replace("</sn>","").to_snake_case())
else:
logger.error("Preprocessor","Failed preprocessing message \"" + msg + "\". (stage SNAKECASE).",false)
core.exception("Preprocessor","Failed parsing snakecase tags in message \"" + msg + "\" (missing end tag?)")
msg_proc = msg
break
else:
break
if verbose_logging:
logger.diag("Preprocessor","Preprocessed snakecasing")
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed snakecase tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
return msg_proc
# Functions to call all other functions related to *case
# Function calls to everything *case-related
func _case(msg:String) -> String:
if verbose_logging:
logger.diag("Preprocessor","Preprocessing casing")
if core.protection_mode: return ""
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing casing tags",false)
var msg_proc = _case_lower(msg)
msg_proc = _case_upper(msg_proc)
msg_proc = _case_camelcase(msg_proc)
msg_proc = _case_pascalcase(msg_proc)
msg_proc = _case_snakecase(msg_proc)
if verbose_logging:
logger.diag("Preprocessor","Preprocessed casing")
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed casing tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
return msg_proc
# Replaces all escapes
func _escapes(msg:String) -> String:
if verbose_logging:
logger.diag("Preprocessor","Preprocessing escapes")
if core.protection_mode: return ""
if diagnostic:logger.diag("CORE/preprocessor.gd","Parsing escape tags",false)
var msg_proc = msg.replace("<esc_nl>","<nl>")
msg_proc = msg_proc.replace("<esc_up>","<up>")
msg_proc = msg_proc.replace("<esc_lo>","<lo>")
@ -332,33 +189,29 @@ func _escapes(msg:String) -> String:
msg_proc = msg_proc.replace("</esc_pa>","</pa>")
msg_proc = msg_proc.replace("</esc_sn>","</sn>")
msg_proc = msg_proc.replace("<esc_np>","<np>")
if verbose_logging:
logger.diag("Preprocessor","Preprocessed escapes")
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed escape tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
return msg_proc
# Checks for <np> and if found returns true, otherwise false
# Checks for <np> tag and if found stops processing
func _noprocess(msg:String) -> bool:
if verbose_logging:
logger.diag("Preprocessor","Preprocessing noprocess")
if core.protection_mode: return true
if diagnostic: logger.diag("CORE/preprocessor.gd","Checking for noprocess tag", false)
if msg.contains("<np>"):
return true
return false
# Executes all preprocessing functions and returns their combined work
func process(msg:String,prefix:String = "",pre_msg:String = "",post_msg:String = "",exclusion_filter:Array = []) -> String:
if verbose_logging:
logger.diag("Preprocessor","Preprocessing a message")
if core.protection_mode: return ""
if diagnostic: logger.diag("CORE/preprocessor.gd","Call to process() recieved",false)
if !enabled:
if verbose_logging:
logger.diag("Preprocessor","Preprocessing failed: Preprocessor is disabled")
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing failed: Preprocessor is disabled",false)
return msg
if _noprocess(msg):
if verbose_logging:
logger.diag("Preprocessor","Preprocessing cancelled: <np> tag detected")
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing stopped: noprocess tag detected", false)
return msg
var msg_proc = _case(msg)
msg_proc = _newline(msg_proc,prefix,pre_msg,post_msg,exclusion_filter)
msg_proc = _escapes(msg_proc)
if verbose_logging:
logger.diag("Preprocessor","Preprocessing complete")
if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing complete", false)
return msg_proc

111
resmgr.gd
View file

@ -1,53 +1,94 @@
# resmgr.gd
# Resource Manager
#
# This file is part of StarOpenSource CORE (SOSCORE)
# Made by the StarOpenSource Project and Contributers
# Licensed under GNU GPLv3
######################################
# 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) #
######################################
extends Node
@onready
var core = get_node(NodePath("/root/core"))
var resources = {}
# CORE modules
var core: Node = null
var logger: Node = null
func initialize() -> void:
if core.protection_mode: return
core.setready()
# Loaded resources list
var resources: Dictionary = {}
func loadres(resname:String,respath:String,replace:bool = false) -> void:
if core.protection_mode: return
if resources.has(resname):
# Config
var config_load_invalid_file_as_null: bool = false
# Loads a resource
func loadres(resource_name:String,resource_path:String,replace:bool = false) -> int:
if core.protection_mode: return 9223372036854775807
logger.diag("CORE/resmgr.gd","Loading resource \"" + resource_name + "\" from path \"" + resource_path + "\" (replace=" + str(replace) + ")")
if resources.has(resource_name):
if replace:
resources.erase(resname)
# If resource is already loaded and replace is true, remove it first (and then add it)
resources.erase(resource_name)
else:
Logger.error("resmgr","Loading \"" + resname + "\" failed: Resource is loaded already")
return
resources.merge({resname:ResourceLoader.load(respath)})
# If resource is already loaded and replace is false, throw an error
var err = core.error("ResourceManager",core.Errors.RESOURCEMANAGER_ALREADY_EXISTS,{"name":resource_name})
logger.error("CORE/resmgr.gd",err["error"])
return err["code"]
# Check if resource exists
if !FileAccess.file_exists(resource_path):
if config_load_invalid_file_as_null:
resources.merge({resource_name:null})
var err = core.error("ResourceManager",core.Errors.RESOURCEMANAGER_INVALID_FILEPATH,{"filepath":resource_path})
logger.error("CORE/resmgr.gd",err["error"])
return err["code"]
# Load the resource
resources.merge({resource_name:ResourceLoader.load(resource_path)})
return core.Errors.OK
func unloadres(resname:String) -> void:
if core.protection_mode: return
if !resources.has(resname):
Logger.error("resmgr","Unloading \"" + resname + "\" failed: Resource is not present")
return
resources.erase(resname)
# Unloads a resource
func unloadres(resource_name:String) -> int:
if core.protection_mode: return 9223372036854775807
if !resources.has(resource_name):
# If resource is not loaded, throw an error
var err = core.error("ResourceManager",core.Errors.RESOURCEMANAGER_RESOURCE_MISSING,{"name":resource_name})
logger.error("CORE/resmgr.gd",err["error"])
return err["code"]
# Unload the resource
resources.erase(resource_name)
return core.Errors.OK
func loadbatch(batch:Dictionary,replace:bool = false) -> void:
if core.protection_mode: return
# Loads a batch of resources
func loadbatch(batch:Dictionary,replace:bool = false) -> int:
if core.protection_mode: return 9223372036854775807
if batch == {}:
Logger.error("resmgr","Loading a batch failed: Batch is empty")
# If batch is empty, throw an error
var err = core.error("ResourceManager",core.Errors.RESOURCEMANAGER_BATCH_EMPTY)
logger.error("CORE/resmgr.gd",err["error"])
return err["code"]
for i in batch:
# Call loadres() method for every item in batch
loadres(i,batch[i],replace)
return core.Errors.OK
func unloadbatch(batch:Array) -> void:
if core.protection_mode: return
# Unloads a batch of resources
func unloadbatch(batch:Array) -> int:
if core.protection_mode: return 9223372036854775807
if batch == []:
Logger.error("resmgr","Unloading a batch failed: Batch is empty")
# If batch is empty, throw an error
var err = core.error("ResourceManager",core.Errors.RESOURCEMANAGER_BATCH_EMPTY)
logger.error("CORE/resmgr.gd",err["error"])
return err["code"]
for i in batch:
# Call unloadres() method for every item in batch
unloadres(i)
return core.Errors.OK
# No set return type here as it can return literally everything.
func getres(resname:String):
# Returns a loaded resource
# No return type is set because it can return literally everything.
func getres(resource_name:String):
if core.protection_mode: return null
if !resources.has(resname):
if !resources.has(resource_name):
# Return null if resource is not loaded
return null
return resources[resname]
# Return the content
return resources[resource_name]

304
smgr.gd
View file

@ -1,169 +1,153 @@
# smgr.gd
# Scene Manager
#
# This file is part of StarOpenSource CORE (SOSCORE)
# Made by the StarOpenSource Project and Contributers
# Licensed under GNU GPLv3
######################################
# 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) #
######################################
extends Node
@onready
var core = get_node(NodePath("/root/core"))
var ccr = null
var ccr_game = null
var ccr_game_inuse = false
var ccr_menu = null
var ccr_menu_names = []
var ccr_cutscene = null
var ccr_cutscene_inuse = false
var ccr_debug = null
var ccr_debug_names = []
# CORE modules
var core: Node = null
var logger: Node = null
var resourcemanager: Node = null
# Overlays
## The debug overlay
var debug_overlay: Node = Node.new()
var debug_overlay_scene: Dictionary = {}
## The cutscene overlay
var cutscene_overlay: Node = Node.new()
var cutscene_overlay_scene: String = ""
## The menu overlay
var menu_overlay: Node = Node.new()
var menu_overlay_scene: Dictionary = {}
## The action overlay
var action_overlay: Node = Node.new()
var action_overlay_scene: String = ""
# Initializes the scene manager
func initialize() -> void:
if core.protection_mode: return
Logger.diag("smgr","Constructing CORE Scene Root (CCR)")
ccr = Control.new()
ccr.name = "ccr"
Logger.diag("smgr","Adding CCR to /root/")
get_tree().root.add_child(ccr)
Logger.diag("smgr","Migrating COREBackground to CCR")
var corebg = get_tree().current_scene
Logger.diag("smgr","Reconstructing COREBackground to CCR")
var corebg_log = corebg.get_node(NodePath("Background/Log")).text
corebg.get_node(NodePath("Background/Log")).rmconnect()
get_tree().current_scene.queue_free()
var corebg_new = ResourceLoader.load("res://CORE/background.tscn").instantiate()
ccr.add_child(corebg_new)
corebg_new.get_node(NodePath("Background/Log")).text = corebg_log
Logger.diag("smgr","COREBackground migration complete.")
Logger.diag("smgr","Adding overlays")
add_overlays()
core.setready()
logger.diag("CORE/smgr.gd","Constructing overlays")
# Set overlay names
debug_overlay.name = "DebugOverlay"
cutscene_overlay.name = "CutsceneOverlay"
menu_overlay.name = "MenuOverlay"
action_overlay.name = "ActionOverlay"
logger.diag("CORE/smgr.gd","Adding overlays")
# Adds overlays to /root/
get_tree().root.add_child(debug_overlay)
get_tree().root.add_child(cutscene_overlay)
get_tree().root.add_child(menu_overlay)
get_tree().root.add_child(action_overlay)
func add_game(resname:String) -> bool:
if core.protection_mode: return false
Logger.diag("smgr","Adding game scene")
if ccr_game_inuse:
Logger.error("smgr","Failed adding game scene: Only one game scene is allowed")
return false
var res = core.resmgr.getres(resname)
if res == null or res.get_class() != "PackedScene":
Logger.error("smgr","Resource is not type of PackedScene")
return false
ccr_game.add_child(res.instantiate())
ccr_game_inuse = true
Logger.diag("smgr","Added game scene")
return true
# Adds a debug scene
func add_debug(resource_name:String) -> int:
if core.protection_mode: return core.Errors.CORE_PROTECTIONMODE
logger.diag("CORE/smgr.gd","Adding debug scene \"" + resource_name + "\"")
# Load resource into memory
var resource: Object = resourcemanager.getres(resource_name)
if resource == null or resource.get_class() != "PackedScene":
# If resource is null (not loaded) or is not a PackedScene, throw an error
var err = core.error("SceneManager",core.Errors.SCENEMANAGER_NOT_PACKEDSCENE,{"scene":resource_name,"overlay":"debug"})
logger.error("CORE/smgr.gd",err["error"])
return err["code"]
if debug_overlay_scene.has(resource_name) and debug_overlay.get_children().has(resource):
# If scene already exists, throw an error
var err = core.error("SceneManager",core.Errors.SCENEMANAGER_ALREADY_LOADED,{"scene":resource_name,"overlay":"debug"})
logger.error("CORE/smgr.gd",err["error"])
return err["code"]
# In theory unecessary but if something for some reason did something very wrong it would be catched here
if !debug_overlay_scene.has(resource_name) and debug_overlay.get_children().has(resource):
core.exception("SceneManager","debug_overlay_scene does not contain \"" + resource_name + "\" but debug_overlay does")
return core.Errors.CORE_EXCEPTION
if debug_overlay_scene.has(resource_name) and !debug_overlay.get_children().has(resource):
core.exception("SceneManager","debug_overlay does not contain \"" + resource_name + "\" but debug_overlay_scene does")
return core.Errors.CORE_EXCEPTION
# Add scene to debug overlay
debug_overlay.add_child(resource)
debug_overlay_scene.merge({resource_name:resource},true)
return core.Errors.OK
func remove_game() -> bool:
if core.protection_mode: return false
Logger.diag("smgr","Removing game scene")
if !ccr_game_inuse:
Logger.error("smgr","Failed removing game scene: No game scene is active")
return false
ccr_game.remove_child(ccr_game.get_child(0))
ccr_game_inuse = false
Logger.diag("smgr","Removed game scene")
return true
# Adds a menu scene
func add_menu(resource_name:String) -> int:
if core.protection_mode: return core.Errors.CORE_PROTECTIONMODE
logger.diag("CORE/smgr.gd","Adding menu scene \"" + resource_name + "\"")
# Load resource into memory
var resource: Object = resourcemanager.getres(resource_name)
if resource == null or resource.get_class() != "PackedScene":
# If resource is null (not loaded) or is not a PackedScene, throw an error
var err = core.error("SceneManager",core.Errors.SCENEMANAGER_NOT_PACKEDSCENE,{"scene":resource_name,"overlay":"menu"})
logger.error("CORE/smgr.gd",err["error"])
return err["code"]
if menu_overlay_scene.has(resource_name) and menu_overlay.get_children().has(resource):
# If resource is null (not loaded) or is not a PackedScene, throw an error
var err = core.error("SceneManager",core.Errors.SCENEMANAGER_ALREADY_LOADED,{"scene":resource_name,"overlay":"menu"})
logger.error("CORE/smgr.gd",err["error"])
return err["code"]
if !menu_overlay_scene.has(resource_name) and menu_overlay.get_children().has(resource):
core.exception("SceneManager","menu_overlay_scene does not contain \"" + resource_name + "\" but menu_overlay does")
return core.Errors.CORE_EXCEPTION
if menu_overlay_scene.has(resource_name) and !menu_overlay.get_children().has(resource):
core.exception("SceneManager","menu_overlay does not contain \"" + resource_name + "\" but menu_overlay_scene does")
return core.Errors.CORE_EXCEPTION
menu_overlay.add_child(resource)
menu_overlay_scene.merge({resource_name:resource},true)
return core.Errors.OK
func add_menu(resname:String) -> bool:
if core.protection_mode: return false
Logger.diag("smgr","Adding menu scene \"" + resname + "\"")
if ccr_menu_names.has(resname):
Logger.error("smgr","Failed adding menu scene: Menu scene with name \"" + resname + "\" already exists")
return false
var res = core.resmgr.getres(resname)
if res == null or res.get_class() != "PackedScene":
Logger.error("smgr","Resource is not type of PackedScene")
return false
ccr_menu.add_child(res.instantiate())
ccr_menu_names.append(resname)
Logger.diag("smgr","Added menu scene \"" + resname + "\"")
return true
# Adds a cutscene scene
func add_cutscene(resource_name:String) -> int:
if core.protection_mode: return core.Errors.CORE_PROTECTIONMODE
logger.diag("CORE/smgr.gd","Adding cutscene scene \"" + resource_name + "\"")
# Load resource into memory
var resource: Object = resourcemanager.getres(resource_name)
if resource == null or resource.get_class() != "PackedScene":
# If resource is null (not loaded) or is not a PackedScene, throw an error
var err = core.error("SceneManager",core.Errors.SCENEMANAGER_NOT_PACKEDSCENE,{"scene":resource_name,"overlay":"cutscene"})
logger.error("CORE/smgr.gd",err["error"])
return err["code"]
if cutscene_overlay_scene == resource_name and cutscene_overlay.get_children().has(resource):
# If resource is null (not loaded) or is not a PackedScene, throw an error
var err = core.error("SceneManager",core.Errors.SCENEMANAGER_ALREADY_LOADED,{"scene":resource_name,"overlay":"cutscene"})
logger.error("CORE/smgr.gd",err["error"])
return err["code"]
if cutscene_overlay_scene != resource_name and cutscene_overlay.get_children().has(resource):
core.exception("SceneManager","cutscene_overlay_scene does not contain \"" + resource_name + "\" but cutscene_overlay does")
return core.Errors.CORE_EXCEPTION
if cutscene_overlay_scene == resource_name and !cutscene_overlay.get_children().has(resource):
core.exception("SceneManager","cutscene_overlay does not contain \"" + resource_name + "\" but cutscene_overlay_scene does")
return core.Errors.CORE_EXCEPTION
cutscene_overlay.add_child(resource)
cutscene_overlay_scene = resource_name
return core.Errors.OK
func remove_menu(scene_name:String) -> bool:
if core.protection_mode: return false
Logger.diag("smgr","Removing menu scene \"" + scene_name + "\"")
if !ccr_menu_names.has(scene_name):
Logger.error("smgr","Failed removing menu scene: Menu scene with name \"" + scene_name + "\" does not exist")
return false
for i in ccr_menu.get_children():
if i.name == scene_name:
ccr_menu.remove_child(i)
break
ccr_menu_names.erase(scene_name)
Logger.diag("smgr","Removed menu scene \"" + scene_name + "\"")
return true
func add_cutscene(resname:String) -> bool:
if core.protection_mode: return false
Logger.diag("smgr","Adding cutscene scene")
if ccr_cutscene_inuse:
Logger.error("smgr","Failed adding cutscene scene: Only one cutscene scene is allowed")
return false
var res = core.resmgr.getres(resname)
if res == null or res.get_class() != "PackedScene":
Logger.error("smgr","Resource is not type of PackedScene")
return false
ccr_cutscene.add_child(res.instantiate())
ccr_cutscene_inuse = true
Logger.diag("smgr","Added cutscene scene")
return true
func remove_cutscene() -> bool:
if core.protection_mode: return false
Logger.diag("smgr","Removing cutscene scene")
if !ccr_cutscene_inuse:
Logger.error("smgr","Failed removing cutscene scene: No cutscene scene is active")
return false
ccr_cutscene.remove_child(ccr_cutscene.get_child(0))
ccr_cutscene_inuse = false
Logger.diag("smgr","Removed cutscene scene")
return true
func add_debug(resname:String) -> bool:
if core.protection_mode: return false
Logger.diag("smgr","Adding debug scene \"" + resname + "\"")
if ccr_debug_names.has(resname):
Logger.error("smgr","Failed adding debug scene: Debug scene with name \"" + resname + "\" already exists")
return false
var res = core.resmgr.getres(resname)
if res == null or res.get_class() != "PackedScene":
Logger.error("smgr","Resource is not type of PackedScene")
return false
ccr_debug.add_child(res.instantiate())
ccr_debug_names.append(resname)
Logger.diag("smgr","Added debug scene \"" + resname + "\"")
return true
func remove_debug(scene_name:String) -> bool:
if core.protection_mode: return false
Logger.diag("smgr","Removing debug scene \"" + scene_name + "\"")
if !ccr_menu_names.has(scene_name):
Logger.error("smgr","Failed removing debug scene: Debug scene with name \"" + scene_name + "\" does not exist")
return false
for i in ccr_debug.get_children():
if i.name == scene_name:
ccr_debug.remove_child(i)
break
ccr_debug_names.erase(scene_name)
Logger.diag("smgr","Removed debug scene \"" + scene_name + "\"")
return true
func add_overlays() -> void:
if core.protection_mode: return
Logger.diag("smgr","Adding game overlay")
ccr_game = Control.new()
ccr_game.name = "GameOverlay"
ccr.add_child(ccr_game)
Logger.diag("smgr","Adding menu overlay")
ccr_menu = Control.new()
ccr_menu.name = "MenuOverlay"
ccr.add_child(ccr_menu)
Logger.diag("smgr","Adding cutscene overlay")
ccr_cutscene = Control.new()
ccr_cutscene.name = "CutsceneOverlay"
ccr.add_child(ccr_cutscene)
Logger.diag("smgr","Adding debug overlay")
ccr_debug = Control.new()
ccr_debug.name = "DebugOverlay"
ccr.add_child(ccr_debug)
# Adds a action scene
func add_action(resource_name:String) -> int:
if core.protection_mode: return core.Errors.CORE_PROTECTIONMODE
logger.diag("CORE/smgr.gd","Adding action scene \"" + resource_name + "\"")
# Load resource into memory
var resource = resourcemanager.getres(resource_name)
if resource == null or typeof(resource) != TYPE_OBJECT or resource.get_class() != "PackedScene":
# If resource is null (not loaded) or is not a PackedScene, throw an error
var err = core.error("SceneManager",core.Errors.SCENEMANAGER_NOT_PACKEDSCENE,{"scene":resource_name,"overlay":"action"})
logger.error("CORE/smgr.gd",err["error"])
return err["code"]
if action_overlay_scene == resource_name and action_overlay.get_children().has(resource):
# If resource is null (not loaded) or is not a PackedScene, throw an error
var err = core.error("SceneManager",core.Errors.SCENEMANAGER_ALREADY_LOADED,{"scene":resource_name,"overlay":"action"})
logger.error("CORE/smgr.gd",err["error"])
return err["code"]
if action_overlay_scene != resource_name and action_overlay.get_children().has(resource):
core.exception("SceneManager","action_overlay_scene does not contain \"" + resource_name + "\" but action_overlay does")
return core.Errors.CORE_EXCEPTION
if action_overlay_scene == resource_name and !action_overlay.get_children().has(resource):
core.exception("SceneManager","action_overlay does not contain \"" + resource_name + "\" but action_overlay_scene does")
return core.Errors.CORE_EXCEPTION
action_overlay.add_child(resource)
action_overlay_scene = resource_name
return core.Errors.OK

View file

@ -1,48 +1,45 @@
# splash.gd
# Splash screen
#
# This file is part of StarOpenSource CORE (SOSCORE)
# Made by the StarOpenSource Project and Contributers
# Licensed under GNU GPLv3
######################################
# 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) #
######################################
extends Node
@onready
var core = get_node("/root/core")
# CORE modules
var core = null
var logger = null
# Config
var config_enabled = null
var config_image = null
var config_image_size = null
var config_color = null
func load_configuration() -> void:
if core.protection_mode: return
config_enabled = core.config.splash_enabled
config_image = core.config.splash_image
config_image_size = core.config.splash_image_size
config_color = core.config.splash_color
func initialize() -> void:
if core.protection_mode: return
apply_config()
if config_enabled:
display()
else:
$Background.visible = false
core.setready()
# Makes the splash screen pretty
func apply_config() -> void:
if core.protection_mode: return
$Background.color = config_color
$Background/Image.texture = ResourceLoader.load(config_image)
$Background/Image.size = Vector2i(config_image_size,config_image_size)
if config_enabled:
display()
else:
$Background.visible = false
# The next two functions are very self explanitory
func display() -> void:
if core.protection_mode: return
Logger.info("splash","Displaying splash screen")
get_tree().root.move_child($"/root/ccr",0)
logger.info("CORE/splash.gd","Displaying splash screen")
get_tree().root.move_child($"/root/CORE/",0)
$Background.visible = true
func dissolve() -> void:
if core.protection_mode: return
Logger.info("splash","Dissolving splash screen")
logger.info("CORE/splash.gd","Dissolving splash screen")
$Background.visible = false

View file

@ -3,7 +3,7 @@
[ext_resource type="Script" path="res://CORE/splash.gd" id="1_n4sar"]
[ext_resource type="Texture2D" path="res://CORE/soscore.png" id="2_5krj5"]
[node name="splash" type="Control"]
[node name="SplashScreen" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0

108
wmgr.gd
View file

@ -1,108 +0,0 @@
# wmgr.gd
# Window Manager
#
# This file is part of StarOpenSource CORE (SOSCORE)
# Made by the StarOpenSource Project and Contributers
# Licensed under GNU GPLv3
extends Node
@onready
var core = get_node(NodePath("/root/core"))
var config_window_size_x = null
var config_window_size_y = null
var config_window_title = null
var config_window_mode = null
var delta = 0
func load_configuration() -> void:
if core.protection_mode: return
config_window_size_x = core.config.wmgr_size_x
config_window_size_y = core.config.wmgr_size_y
config_window_title = core.config.wmgr_title
config_window_mode = core.config.wmgr_mode
func initialize() -> void:
if core.protection_mode: return
Logger.diag("wmgr","Configuring window")
DisplayServer.window_set_size(Vector2i(config_window_size_x,config_window_size_y))
DisplayServer.window_set_min_size(Vector2i(960,540))
DisplayServer.window_set_title(config_window_title)
DisplayServer.window_set_mode(config_window_mode)
core.setready()
func _process(deltap) -> void:
delta = deltap
func set_size(x:int,y:int) -> void:
if core.protection_mode: return
Logger.diag("wmgr","Applying new window size (" + str(x) + "x" + str(y) + ")")
DisplayServer.window_set_size(Vector2i(x,y))
func set_position(x:int,y:int) -> void:
if core.protection_mode: return
Logger.diag("wmgr","Applying new window position (X" + str(x) + " Y" + str(y) + ")")
DisplayServer.window_set_position(Vector2i(x,y))
func set_title(title:String) -> void:
if core.protection_mode: return
Logger.diag("wmgr","Applying new window title (" + title + ")")
DisplayServer.window_set_title(title)
config_window_title = title
func set_mode(mode:String) -> bool:
if core.protection_mode: return false
Logger.diag("wmgr","Applying new window mode (" + mode + ")")
match(mode):
"WINDOWED": DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
"MINIMIZED": DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_MINIMIZED)
"MAXIMIZED": DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_MAXIMIZED)
"FULLSCREEN": DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
"EXCLUSIVE_FULLSCREEN": DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_EXCLUSIVE_FULLSCREEN)
_:
Logger.error("wmgr","Invalid window mode \"" + mode + "\".")
return false
return true
func get_size() -> Vector2i:
if core.protection_mode: return Vector2i(0,0)
return DisplayServer.window_get_size()
func get_position() -> Vector2i:
if core.protection_mode: return Vector2i(0,0)
return DisplayServer.window_get_position()
func get_title() -> String:
if core.protection_mode: return ""
return config_window_title
func get_mode() -> String:
if core.protection_mode: return ""
match(DisplayServer.window_get_mode()):
0: return "WINDOWED"
1: return "MINIMIZED"
2: return "MAXIMIZED"
3: return "FULLSCREEN"
4: return "EXCLUSIVE_FULLSCREEN"
_:
core.exception("wmgr","The window mode id \"" + str(DisplayServer.window_get_mode()) + "\" is not known to wmgr.gd")
return "INVALID_MODE"
func get_fps(flat:bool = false) -> float:
if core.protection_mode: return 0.0
if str(delta) == "0":
return INF
else:
if flat:
return float(int(1/delta))
else:
return 1/delta
func get_rendertime() -> float:
if core.protection_mode: return 0.0
return Performance.get_monitor(Performance.TIME_PROCESS)
func get_delta() -> float:
if core.protection_mode: return 0.0
return delta