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 *.import
config.gd config.gd
devprj

View file

@ -1,8 +1,9 @@
#!/bin/make #!/bin/make
CORE=$(shell pwd) CORE=$(shell pwd)
ASSETS=$(CORE)/assets
DOCSCONF=$(CORE)/mkdocs.yml DOCSCONF=$(CORE)/mkdocs.yml
DOCSOUT=$(CORE)/docs_out DOCSOUT=$(CORE)/docs_out
TESTPROJECT=/tmp/core_devproject TESTPROJECT=$(CORE)/devprj
dist: help dist: help
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 @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: docs-serve:
@echo ":: Serving documentation, press CTRL+C to exit" @echo ":: Serving documentation, press CTRL+C to exit"
# prevent make from terminating
@bash -c "mkdocs serve --dirtyreload --config-file "$(DOCSCONF)";exit 0" @bash -c "mkdocs serve --dirtyreload --config-file "$(DOCSCONF)";exit 0"
docs-build: docs-build:
@make docs-clean @make docs-clean
@ -34,16 +34,12 @@ docs-clean:
@rm -rf "$(DOCSOUT)" @rm -rf "$(DOCSOUT)"
mkdevprj: mkdevprj:
@echo ":: Creating development project" @echo ":: Creating development project"
@mkdir -p $(TESTPROJECT)/mods/testmod/ @cp -r $(ASSETS)/testproject $(TESTPROJECT)
@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"
@ln -s $(CORE) $(TESTPROJECT)/CORE @ln -s $(CORE) $(TESTPROJECT)/CORE
@mv $(TESTPROJECT)/config.gd $(TESTPROJECT)/CORE/config.gd
@echo ":: Development project created." @echo ":: Development project created."
@echo " You can now launch Godot and open '$(TESTPROJECT)'." @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: rmdevprj:
@echo ":: Removing development project" @echo ":: Removing development project"
@echo ":: !!!!!!!!!!!!!!!!!!!!!!!!!!!!" @echo ":: !!!!!!!!!!!!!!!!!!!!!!!!!!!!"

View file

@ -11,15 +11,15 @@ CORE is under heavy development and can be very unstable. Please do not use CORE
- Notification API - Notification API
- Basic debugging tool (CTRL+C to crash, F3 to toggle statistics) - Basic debugging tool (CTRL+C to crash, F3 to toggle statistics)
- ~~Better documentation (docs4everything)~~ - ~~Better documentation (docs4everything)~~
- Everything commented and explained - ~~Everything commented and explained~~
- Documentation page explaining what does what (for CORE noobies) - Documentation page explaining what does what (for CORE noobies)
- ~~Autoload singleton check removal~~ - ~~Autoload singleton check removal~~
- More wmgr functions - ~~More wmgr functions~~ (the window manager got removed in the rewrite)
- ~~Website~~ - ~~Website~~
- ~~Silencing startup messages (info -> diag)~~ - ~~Silencing startup messages (info -> diag)~~
- ~~Remove autoload component~~ - ~~Remove autoload component~~
- ~~Fix syntax (set return types missing)~~ - ~~Fix syntax (set return types missing)~~
- Much more configuration options - ~~Much more configuration options~~ (CORE's already pretty configurable)
- Implement preprocessor placeholders - Implement preprocessor placeholders
- Clipboard content - Clipboard content
- CORE version - 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. Yes, in theory you can refactor your entire codebase and make a giant mess, but we don't recommend doing that.
# Requirements # Requirements
- Godot 4.0/4.1 (stable releases only) - Godot 4.1 (stable releases only)
- Good experience with Godot 4 and GDScript - Good experience with Godot 4 and GDScript
# Recommendations # Recommendations
- Use smgr instead of manually managing scenes or CORE will break apart. If you don't want headaches, use smgr. - 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 logger for logging. It supports rich formatting (using tags, handled by our Preprocessor™) and is generally better than using print() for everything. - 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.
- Use wmgr for managing the main window title, size, position, etc.
# How to install # How to install
- Download the [CORE manager](https://git.staropensource.de/StarOpenSource/core-manager#download) and open it - 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) # THE CORE FRAMEWORK #
# # MADE BY THE STAROPENSOURCE PROJECT #
# This file is part of StarOpenSource CORE (SOSCORE) # AND CONTRIBUTERS (THANK YOU!) #
# Made by the StarOpenSource Project and Contributers # #
# Licensed under GNU GPLv3 # COPYRIGHT 2023 THE STAROPENSOURCE #
# PROJECT AND CONTRIBUTERS #
# #
# LICENSED UNDER THE GNU GENERAL #
# PUBLIC LICENSE VERSION 3 (ONLY) #
######################################
extends Node extends Node
@onready # CORE modules
var core = get_node("/root/core") var core: Node = null
var logger: Node = null
# Configuration
var config_loadpath = null var config_loadpath = null
var config_wanted_name = null var config_wanted_name = null
var config_wanted_version = null var config_wanted_version = null
var config_wanted_api = null var config_wanted_api = null
# Modification list
var modlist = [] var modlist = []
# Hook list
var hooks = {} var hooks = {}
func load_mods() -> Array: func load_mods() -> Array:
if core.protection_mode: return [] if core.protection_mode: return []
var errors = [] var errors: Array = []
for directory in DirAccess.get_directories_at(config_loadpath): 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 != "": if return_value != "":
errors.append(return_value) errors.append(return_value)
return errors return errors
func load_mod(mod_name:String) -> String: 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): 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"): 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" 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_raw: FileAccess = FileAccess.open(config_loadpath + "/" + mod_name + "/" + config_wanted_name + ".coremod",FileAccess.READ)
var modinfo = modinfo_raw.get_as_text() var modinfo: Dictionary = JSON.parse_string(modinfo_raw.get_as_text())
modinfo_raw.close() modinfo_raw.close()
modinfo = JSON.parse_string(modinfo)
if modinfo == null: 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 return "Failed modinfo parsing for modification located at " + config_loadpath + "/" + mod_name
if !modinfo.has_all(["wanted","mod"]): 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" 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"]): 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." 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"]): 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." 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: 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) 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: 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) 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"]): 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" 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_script: Script = ResourceLoader.load(config_loadpath + "/" + mod_name + "/" + modinfo["mod"]["entrypoint"])
var entrypoint = Control.new() var entrypoint: Node = Node.new()
entrypoint.name = mod_name entrypoint.name = mod_name
entrypoint.set_script(entrypoint_script) entrypoint.set_script(entrypoint_script)
get_tree().root.add_child(entrypoint) 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 == "": if mod_err == "":
modlist.append(mod_name) modlist.append(mod_name)
return "" return ""
@ -77,11 +85,11 @@ func unload_mods() -> void:
await unload_mod(mod) await unload_mod(mod)
func unload_mod(mod_name:String) -> void: 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): 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: 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 return
await get_node("/root/" + mod_name)._stop() await get_node("/root/" + mod_name)._stop()
get_tree().root.remove_child(get_node("/root/" + mod_name)) 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: func register_hook(mod_name:String,hook_name:String,hook_action:int,method:Callable) -> bool:
if !modlist.has(mod_name): 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 return false
if hooks.has(hook_name): core.exception("CORE/cml.gd","Function not implemented")
Logger.error("moam","Failed registering hook \"" + hook_name + "\" for mod \"" + mod_Name + "\" as the hook already exists")
return true return true
func get_list() -> Array: func get_list() -> Array:
@ -101,23 +108,19 @@ func get_list() -> Array:
func get_info(mod_name:String) -> Dictionary: func get_info(mod_name:String) -> Dictionary:
if !modlist.has(mod_name): if !modlist.has(mod_name):
return {"error":"Modification \"" + mod_name + "\" is not loaded"} 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_raw: FileAccess = FileAccess.open(config_loadpath + "/" + mod_name + "/" + config_wanted_name + ".coremod",FileAccess.READ)
var modinfo = JSON.parse_string(modinfo_raw.get_as_text()) var modinfo: Dictionary = JSON.parse_string(modinfo_raw.get_as_text())
modinfo_raw.close() modinfo_raw.close()
if modinfo == null: if modinfo == null:
return {"error":"Failed parsing modinfo for modification \"" + modinfo + "\""} return {"error":"Failed parsing modinfo for modification \"" + mod_name + "\""}
return modinfo return modinfo
func load_configuration() -> void: func load_configuration() -> void:
if core.protection_mode: return if core.protection_mode: return
config_loadpath = core.config.moam_loadpath config_loadpath = core.config.cml_loadpath
config_wanted_name = core.config.moam_wanted_name config_wanted_name = core.config.cml_wanted_name
config_wanted_version = core.config.moam_wanted_version config_wanted_version = core.config.cml_wanted_version
if core.config.get("moam_wanted_api") == null: if core.config.get("cml_wanted_api") == null:
config_wanted_api = config_wanted_version config_wanted_api = config_wanted_version
else: else:
config_wanted_api = core.config.moam_wanted_api config_wanted_api = core.config.cml_wanted_api
func initialize() -> void:
if core.protection_mode: return
core.setready()

242
core.gd
View file

@ -1,90 +1,120 @@
# core.gd ######################################
# CORE Holder # THE CORE FRAMEWORK #
# # MADE BY THE STAROPENSOURCE PROJECT #
# This file is part of StarOpenSource CORE (SOSCORE) # AND CONTRIBUTERS (THANK YOU!) #
# Made by the StarOpenSource Project and Contributers # #
# Licensed under GNU GPLv3 # COPYRIGHT 2023 THE STAROPENSOURCE #
# PROJECT AND CONTRIBUTERS #
# #
# LICENSED UNDER THE GNU GENERAL #
# PUBLIC LICENSE VERSION 3 (ONLY) #
######################################
extends Node extends Node
const version = "source 0" # CORE modules
var protection_mode = false var logger: Node = null
var locked = false var preprocessor: Node = null
var readycount = 0 var config: Node = null
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}
func attach(type:String,module,do_setup:bool = true) -> void: # Version
if protection_mode: return const version: Dictionary = {"type":"source","releasebuild":0,"full":"source 0"}
if locked: # Protection mode
return var protection_mode: bool = false
Logger.diag("core","Attaching " + type + " to CORE") # Development mode
var mod = module var development_mode: bool = false
if do_setup: # Loadpath (from coreinit.gd)
mod = Control.new() var loadpath: String = ""
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")
func setready() -> void: # Errors
if protection_mode: return enum Errors {
readycount = readycount+1 OK,
if readycount == 7: CORE_PROTECTIONMODE,
readylized = true CORE_EXCEPTION,
CORE_INVALID_MODULE,
func lock() -> void: RESOURCEMANAGER_ALREADY_EXISTS,
if protection_mode: return RESOURCEMANAGER_INVALID_FILEPATH,
locked = true RESOURCEMANAGER_RESOURCE_MISSING,
Logger.diag("core","CORE is now locked. No new attachments can be added.") RESOURCEMANAGER_BATCH_EMPTY,
SCENEMANAGER_ALREADY_LOADED,
SCENEMANAGER_NOT_LOADED,
SCENEMANAGER_NOT_PACKEDSCENE
}
func welcome() -> void: func welcome() -> void:
if protection_mode: return 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 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]################################ [color=red]################################
EXCEPTION! EXCEPTION! EXCEPTION! EXCEPTION! EXCEPTION! EXCEPTION!
The CORE Framework experienced a critical error in runtime. The CORE Framework experienced a critical error in runtime.
Please report this crash to the CORE Framework repository (with %submit_issue%
the full log file). You can submit a crash report at:
https://git.staropensource.de/StarOpenSource/core/issues/new
CORE INFORMATION CORE INFORMATION
version = "%version%" version = "%version%"
readylized = %readylized% development_mode = %development_mode%
readycount = %readycount%
locked = %locked%
preprocessor_enabled = %preprocessor_enabled% preprocessor_enabled = %preprocessor_enabled%
preprocessor_tests = %preprocessor_tests% preprocessor_diagnostic = %preprocessor_diagnostic%
preprocessor_tests_executed = %preprocessor_tests_executed%
preprocessor_tests_success = %preprocessor_tests_success%
logger_enabled = %logger_enabled% logger_enabled = %logger_enabled%
logger_diag = %logger_diag% logger_diagnostic = %logger_diagnostic%
OPERATING SYSTEM OPERATING SYSTEM
timezone = %timezone% timezone = %timezone%
@ -110,7 +140,7 @@ permissions = %permissions%
debug_build = %debug_build% debug_build = %debug_build%
ERROR INFORMATION ERROR INFORMATION
script = "%script%" module = "%module%"
error = "%error%" error = "%error%"
STACKTRACE STACKTRACE
@ -119,17 +149,16 @@ STACKTRACE
EXCEPTION! EXCEPTION! EXCEPTION! EXCEPTION! EXCEPTION! EXCEPTION!
################################ ################################
""" """
if development_mode:
exc_message = exc_message.replace("%version%",version) exc_message = exc_message.replace("%submit_issue%",submit_issue_devmode)
exc_message = exc_message.replace("%readylized%",str(readylized)) else:
exc_message = exc_message.replace("%readycount%",str(readycount)) exc_message = exc_message.replace("%submit_issue%",submit_issue_default)
exc_message = exc_message.replace("%locked%",str(locked)) exc_message = exc_message.replace("%version%",version["full"])
exc_message = exc_message.replace("%preprocessor_enabled%",str(Preprocessor.enabled)) exc_message = exc_message.replace("%development_mode%",str(development_mode))
exc_message = exc_message.replace("%preprocessor_tests%",str(Preprocessor.tests_enabled)) exc_message = exc_message.replace("%preprocessor_enabled%",str(preprocessor.enabled))
exc_message = exc_message.replace("%preprocessor_tests_executed%",str(Preprocessor.tests_executed)) exc_message = exc_message.replace("%preprocessor_diagnostic%",str(preprocessor.diagnostic))
exc_message = exc_message.replace("%preprocessor_tests_success%",str(Preprocessor.tests_success)) exc_message = exc_message.replace("%logger_enabled%",str(logger.enabled))
exc_message = exc_message.replace("%logger_enabled%",str(Logger.enable)) exc_message = exc_message.replace("%logger_diagnostic%",str(logger.diagnostic))
exc_message = exc_message.replace("%logger_diag%",str(Logger.enable_diag))
exc_message = exc_message.replace("%timezone%",str(Time.get_time_zone_from_system())) 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)) 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("%permissions%",str(OS.get_granted_permissions()))
exc_message = exc_message.replace("%debug_build%",str(OS.is_debug_build())) exc_message = exc_message.replace("%debug_build%",str(OS.is_debug_build()))
exc_message = exc_message.replace("%script%",script) exc_message = exc_message.replace("%module%",module)
exc_message = exc_message.replace("%error%",error) exc_message = exc_message.replace("%error%",exception_error)
exc_message = exc_message.replace("%stacktrace%",str(get_stack())) exc_message = exc_message.replace("%stacktrace%",str(get_stack()))
print_rich(exc_message) print_rich(exc_message)
await get_tree().create_timer(0.25).timeout await get_tree().create_timer(0.25).timeout
get_tree().quit(255) get_tree().quit(255)
func error(module:String,respo:Responsibilities,error:Errors,error_info:Dictionary = {}) -> Dictionary: func error(module:String,error_enum:Errors,error_info:Dictionary = {}) -> Dictionary:
var error_text = "" match(error_enum):
match(respo): Errors.OK:
Responsibilities["UNKNOWN"]: exception("core","Module \"" + module + "\" tried recieving information about error OK (are you ok?)")
pass Errors.CORE_PROTECTIONMODE:
match(error): return {"code":9223372036854775807,"error":"CORE is in protection mode and is unavailable"}
Errors["UNKNOWN"]: Errors.CORE_EXCEPTION:
error_text = "" 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) + "\"") 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 # THE CORE FRAMEWORK #
# # MADE BY THE STAROPENSOURCE PROJECT #
# This file is part of StarOpenSource CORE (SOSCORE) # AND CONTRIBUTERS (THANK YOU!) #
# Made by the StarOpenSource Project and Contributers # #
# Licensed under GNU GPLv3 # COPYRIGHT 2023 THE STAROPENSOURCE #
# PROJECT AND CONTRIBUTERS #
# #
# LICENSED UNDER THE GNU GENERAL #
# PUBLIC LICENSE VERSION 3 (ONLY) #
######################################
extends Node extends Node
@onready var loadpath: String = "res://CORE/"
var engine_version = Engine.get_version_info()
# 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: 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") print("coreinit -> Checking CORE requirements")
# Check if Godot major version is exactly 4
if engine_version["major"] != 4: if engine_version["major"] != 4:
print("coreinit -> CORE only supports Godot 4. Please upgrade/downgrade your Godot Project to Godot 4.") print("coreinit -> Error: CORE only supports Godot 4.1.stable releases.")
await get_tree().create_timer(0.1).timeout return false
get_tree().quit(141) # Check if Godot minor version is exactly 1
return if engine_version["minor"] != 1:
if engine_version["minor"] != 0 and engine_version["minor"] != 1: print("coreinit -> Error: CORE only supports Godot 4.1.stable releases.")
print("coreinit -> CORE only supports Godot 4.0 and 4.1. Please upgrade/downgrade your Godot Project to Godot 4.0 or 4.1.") return false
await get_tree().create_timer(0.1).timeout # Check if Godot release channel is "stable"
get_tree().quit(142)
return
if engine_version["status"] != "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.") print("coreinit -> Error: CORE only supports Godot 4.1.stable releases.")
await get_tree().create_timer(0.1).timeout return false
get_tree().quit(143) # Display warning if autoloads are used
return if get_tree().root.get_child_count(true) != 2:
if get_node_or_null(NodePath("/root/Logger")) == null: print("coreinit -> Warning: We do not recommend using autoloads in your project as bugs may occur.")
print("coreinit -> The CORE logger is missing in your autoload project settings!") # Check if configuration file exists
await get_tree().create_timer(0.1).timeout if !FileAccess.file_exists(loadpath + "config.gd"):
get_tree().quit(144) print("coreinit -> Error: The CORE configuration file is missing. Use CORE Manager to repair your project.")
return return false
if get_node_or_null(NodePath("/root/Preprocessor")) == null: # Success!
print("coreinit -> The CORE preprocessor is missing in your autoload project settings!") return true
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"))

View file

@ -2,13 +2,10 @@
[ext_resource type="Script" path="res://CORE/coreinit.gd" id="1_ubktt"] [ext_resource type="Script" path="res://CORE/coreinit.gd" id="1_ubktt"]
[node name="coreinit" type="Control"] [node name="coreinit" type="Node"]
layout_mode = 3
anchors_preset = 0
script = ExtResource("1_ubktt") script = ExtResource("1_ubktt")
[node name="ColorRect" type="ColorRect" parent="."] [node name="ColorRect" type="ColorRect" parent="."]
layout_mode = 0
offset_left = -5e+08 offset_left = -5e+08
offset_top = -5e+08 offset_top = -5e+08
offset_right = 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 # THE CORE FRAMEWORK #
# # MADE BY THE STAROPENSOURCE PROJECT #
# This file is part of StarOpenSource CORE (SOSCORE) # AND CONTRIBUTERS (THANK YOU!) #
# Made by the StarOpenSource Project and Contributers # #
# Licensed under GNU GPLv3 # COPYRIGHT 2023 THE STAROPENSOURCE #
extends RichTextLabel # PROJECT AND CONTRIBUTERS #
# #
# LICENSED UNDER THE GNU GENERAL #
# PUBLIC LICENSE VERSION 3 (ONLY) #
######################################
extends Node
var log_prefix = "" # CORE modules
var log_suffix = "" var core: Node = null
var logger: Node = null
func _ready() -> void: # Initializes CORELog
# Enable recieving of log messages func initialize() -> void:
Logger.connect("logevent",Callable(self,"logevent")) if core.protection_mode: return
# Disable VScrollBar functionality & visibility # logevent (signal) -> logupdate()
get_child(0,true).add_theme_stylebox_override("grabber",StyleBoxEmpty.new()) logger.connect("logevent",Callable(self,"logupdate"))
get_child(0,true).add_theme_stylebox_override("grabber_highlight",StyleBoxEmpty.new())
get_child(0,true).add_theme_stylebox_override("grabber_pressed",StyleBoxEmpty.new()) # Activate auto scrolling
get_child(0,true).add_theme_stylebox_override("scroll",StyleBoxEmpty.new()) $Background/Log.scroll_active = true
get_child(0,true).add_theme_stylebox_override("scroll_focus",StyleBoxEmpty.new()) $Background/Log.scroll_following = true
get_child(0,true).set_deferred("size",Vector2i(0,0)) # Disable mouse influence
get_child(0,true).mouse_filter = Control.MOUSE_FILTER_IGNORE $Background/Log.mouse_filter = Control.MOUSE_FILTER_IGNORE
# Make RichTextLabel ignore all mouse events (to disable scrolling) $Background/Log.get_child(0,true).mouse_filter = Control.MOUSE_FILTER_IGNORE
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: # Updates log text
var windowsize = DisplayServer.window_get_size() func logupdate(_type:String,_script:String,_method:String,logmessage:String) -> void:
$".".size = windowsize $Background/Log.text = $Background/Log.text + "\n" + logmessage
get_parent().size = windowsize
get_parent().get_parent().size = windowsize
func logevent(_type:String,_script:String,_message:String,logcomp:String) -> void: # These two functions are very self explanitory
# Appends log to RichTextLabel func display() -> void:
text = text + "\n" + log_prefix + logcomp + log_suffix if core.protection_mode: return
$Background.visible = true
func rmconnect() -> void: func dissolve() -> void:
# Disables recieving of log messages if core.protection_mode: return
Logger.disconnect("logevent",Callable(self,"logevent")) $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 #!/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() { function dircount() {
if [ "$VERBOSE" == "true" ]; then echo ":: Checking directory \"$*\"..."; fi if [ "$VERBOSE" == "true" ]; then echo ":: Checking directory \"$*\"..."; fi
cd "$*" || exit 54 cd "$*" || exit 54
for file in $FILEEXTENSION; do for file in $FILEEXTENSION; do
export "file_full=$*/$file" export "file_full=$*/$file"
if [ -d "$file" ]; then 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 elif [ -f "$file" ]; then
if [ "$IGNORE_SCRIPT" == "true" ] && [ "$file" == "count_characters.sh" ]; then if [ "$IGNORE_SCRIPT" == "true" ] && [ "$file" == "count_characters.sh" ]; then
if [ "$VERBOSE" == "true" ]; then echo ":: Skipping this script"; fi 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. Welcome to the StarOpenSource documentation! Look below for more information about CORE and code references.
## What, why, wtf? ## 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? ## 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? ## Can I use CORE in my project freely?
[Click this text to learn more about licensing.](/licensing/) [Click this text to learn more about licensing.](/licensing/)
## I have a problem with CORE! ## 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? ## 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. 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 - navigation
--- ---
# Installing CORE # 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/> 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) #### 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/b0/CORE-Manager.elf) #### 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` #### 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. 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.** **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`. 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 ### Step 4: Write your init script
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/). 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
## Step 5: Write your init script
Create a new GDScript file and write this into it:
``` gdscript
extends Node extends Node
@onready @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: func _ready() -> void:
core.welcome() #(2)! core.welcome() #(3)!
Logger.enable_diag = true #(3)! config.logger_diagnostic = true #(4)!
Logger.diag("<your_script_name>","This is a diagnostic message. I can only be seen with Logger.enable_diag being true.") core.reload_config() #(5)!
Logger.info("<your_script_name>","This is a informational message.") logger.diag("<your_script_name>","This is a diagnostic message. I can only be seen if diagnostic log messages are enabled.")
Logger.warn("<your_script_name>","This is a warning message.") logger.info("<your_script_name>","This is a informational message.")
Logger.error("<your_script_name>","This is a error message.") logger.warn("<your_script_name>","This is a warning message.")
await get_tree().create_timer(0.1).timeout #(4)! logger.error("<your_script_name>","This is a error message.")
get_tree().quit(0) core.exit_safely() #(6)!
``` ```
1. Imports the CORE Holder aka. /root/core 1. Imports the CORE "module" aka. /root/CORE
2. Makes CORE say hello :) 2. Imports the CORE's logger implementation
3. Enables diagnostic log output 3. Makes CORE say hello :)
4. Waits 100 milliseconds for the log messages to be printed before exiting 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 ### Step 5: 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`): Start your project and wait at least 500ms. You should see this output in your Godot console (with a few variations, of course):
``` text ```text
logger -> Initializing Logger coreinit -> "Fixing" busy setting up children issue #(1)!
preprocessor -> Initializing Preprocessor coreinit -> Bootstrapping CORE
preprocessor -> Delaying initialization by 0.75s
coreinit -> Checking CORE requirements coreinit -> Checking CORE requirements
coreinit -> Constructing coreloader coreinit -> Loading modules
coreinit -> Injecting coreloader coreinit -> Constructing modules
coreinit -> Switching to COREBackground coreinit -> Injecting modules
(core) [INFO] CORE git-develop welcomes you! coreinit -> Updating dependency references
It seems like everything is working :) coreinit -> Applying configuration to base modules
(<your_script_name>) [DIAG] This is a diagnostic message. I can only be seen with Logger.enable_diag being true. coreinit -> Initializing base modules
(<your_script_name>) [INFO] This is a informational message. (CORE/core.gd) [INFO] CORE (source 0) welcomes you! #(2)!
(<your_script_name>) [WARN] This is a warning message. It seems like everything is working :)
(<your_script_name>) [ERROR] This is a error message. (init.gd) [DIAG] This is a diagnostic message. I can only be seen if diagnostic log messages are enabled.
(coreloader) [DIAG] Removing coreloader (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). 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 ## 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? ## 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. 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: hide:
- navigation - navigation
--- ---
# Resource Manager (core.resmgr) # Resource Manager (/root/CORE/ResourceManager)
Responsible for loading and unloading resources, even in batches. Responsible for loading and unloading resources, even in batches.
## Methods ## Methods
@ -54,17 +54,3 @@ Responsible for loading and unloading resources, even in batches.
- type `String` - type `String`
- mandatory `yes` - mandatory `yes`
- description `The resource name.` - 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 - navigation
--- ---
# References index # References index
Here you can find all code references.<br/> Welcome to the reference documentation! Here you can find everything you need to develop your game or application with CORE.
**Index syntax**: *Human-friendly name (callable_gdscript.name)*
## [CORE configuration file (core.config)](/references/config.gd/) ## [The CORE configuration file](/references/Configuration_File/)
## [CORE Holder (core)](/references/core.gd/) ## [CORE](/references/CORE/)
## [Events (core.events)](/references/events.gd/) ## [Logger](/references/Logger/)
## [Preprocessor (Preprocessor)](/references/preprocessor.gd/) ## [Preprocessor](/references/Preprocessor/)
## [Resource Manager (core.resmgr)](/references/resmgr.gd/) ## [Resource Manager](/references/ResourceManager/)
## [Scene Manager (core.smgr)](/references/smgr.gd/) ## [Scene Manager](/references/SceneManager/)
## [Splash Screen (core.splash)](/references/splash.gd/) ## [Splash Screen](/references/SplashScreen/)
## [Window Manager (core.wmgr)](/references/wmgr.gd/) ## [Debug Display](/references/DebugDisplay/)
## [Mother Of All Mods [Mod loader] (core.moam)](/references/moam.gd/) ## [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 # 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). **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 ## Work In Progress
### (wmgr) [ERROR] Invalid window mode "`<PLACEHOLDER>`". 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.
[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.

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**. 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/) ### [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 # THE CORE FRAMEWORK #
# # MADE BY THE STAROPENSOURCE PROJECT #
# This file is part of StarOpenSource CORE (SOSCORE) # AND CONTRIBUTERS (THANK YOU!) #
# Made by the StarOpenSource Project and Contributers # #
# Licensed under GNU GPLv3 # COPYRIGHT 2023 THE STAROPENSOURCE #
# PROJECT AND CONTRIBUTERS #
# #
# LICENSED UNDER THE GNU GENERAL #
# PUBLIC LICENSE VERSION 3 (ONLY) #
######################################
extends Node extends Node
@onready # CORE modules
var core = get_node(NodePath("/root/core")) var core: Node = null
var window_title_prev = "" var logger: Node = null
var window_size_x_prev = 0
var window_size_y_prev = 0
var window_pos_x_prev = 0
var window_pos_y_prev = 0
# 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_title
signal window_size signal window_size
signal window_pos signal window_pos
@ -23,52 +32,64 @@ signal logger_info
signal logger_warn signal logger_warn
signal logger_error signal logger_error
# Set up connection between logger's logevent and logger_update()
func initialize() -> void: func initialize() -> void:
if core.protection_mode: return if core.protection_mode: return
Logger.connect("logevent",Callable(self,"logger_update")) # logevent (signal) -> logger_update()
core.setready() logger.connect("logevent",Callable(self,"logger_update"))
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
func logger_update(type:String,script:String,message:String,_logmessage:String) -> void: func logger_update(type:String,script:String,message:String,_logmessage:String) -> void:
if core.protection_mode: return if core.protection_mode: return
# Emit signal logger_all for all log messages
emit_signal("logger_all",type,script,message) emit_signal("logger_all",type,script,message)
# Check for log type and emit the right signal
if type == "DIAG": if type == "DIAG":
emit_signal("logger_diag",script,message) emit_signal("logger_diag",script,message)
elif type == "INFO": elif type == "INFO":
emit_signal("logger_info",script,message) emit_signal("logger_info",script,message)
elif type == "WARN": elif type == "WARN":
emit_signal("logger_warn",script,message) emit_signal("logger_warn",script,message)
elif type == "ERROR": elif type == "ERR!":
emit_signal("logger_error",script,message) emit_signal("logger_error",script,message)
else: else:
core.exception("events","The log type \"" + type + "\" is not known to events.gd") 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 # THE CORE FRAMEWORK #
# # MADE BY THE STAROPENSOURCE PROJECT #
# This file is part of StarOpenSource CORE (SOSCORE) # AND CONTRIBUTERS (THANK YOU!) #
# Made by the StarOpenSource Project and Contributers # #
# Licensed under GNU GPLv3 # COPYRIGHT 2023 THE STAROPENSOURCE #
extends Control # 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 signal logevent
@onready func initialize() -> void:
var preprocessor = get_node(NodePath("/root/Preprocessor")) if core.protection_mode: return
@export if preprocessor == null:
@export_category("Configuration") return
# Enables/disables logging diag("CORE/logger.gd","Logger is ready.")
var enable = true
@export
@export_category("Configuration")
# Enables/disables diagnostic/verbose logging
var enable_diag = false
# Initializes the func diag(script:String,message:String,preproc:bool = true) -> void:
func _ready() -> void: if core.protection_mode: return
print("logger -> Initializing Logger") # Check if both the logger and diagnostic log messages are enabled
if get_node_or_null(NodePath("/root/Preprocessor")) == null: if enabled and diagnostic:
print("logger -> Preprocessor is not loaded. Shutting application down...") # Check if preprocessing is allowed for this message and if the preprocessor is enabled
get_tree().quit(1) if preproc and preprocessor.enabled:
await get_tree().create_timer(1).timeout # Run the message through the preprocessor if enabled/allowed
diag("Logger","Logger is ready.") var logmsg: String = preprocessor.process(message,"[color=gray](" + script + ") [DIAG] [/color]","[color=gray][b]","[/b][/color]",["[color=gray]","[/color]"])
# Print the message
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]"])
print_rich(logmsg) print_rich(logmsg)
# Emit logevent signal
emit_signal("logevent","DIAG",script,message,logmsg) emit_signal("logevent","DIAG",script,message,logmsg)
else: else:
var logmsg = "[color=gray](" + script + ") [DIAG] [b]" + message + "[/b][/color]" # Construct a log message normally if preprocessor is disabled/disallowed
print_rich(logmsg) # 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) emit_signal("logevent","DIAG",script,message,logmsg)
func info(script:String,message:String,preproc:bool = true) -> void: func info(script:String,message:String,preproc:bool = true) -> void:
if enable: if core.protection_mode: return
if preproc and Preprocessor.enabled: # Check if the logger is enabled
var logmsg = preprocessor.process(message,"[color=white](" + script + ") [INFO] [/color]","[color=white][b]","[/b][/color]",["[color=white]","[/color]"]) 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) print_rich(logmsg)
# Emit logevent signal
emit_signal("logevent","INFO",script,message,logmsg) emit_signal("logevent","INFO",script,message,logmsg)
else: else:
var logmsg = "(" + script + ") [INFO] [b]" + message + "[/b]" # Construct a log message normally if preprocessor is disabled/disallowed
print_rich(logmsg) # 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) emit_signal("logevent","INFO",script,message,logmsg)
func warn(script:String,message:String,preproc:bool = true) -> void: func warn(script:String,message:String,preproc:bool = true) -> void:
if enable: if core.protection_mode: return
if preproc and Preprocessor.enabled: # Check if the logger is enabled
var logmsg = preprocessor.process(message,"[color=orange](" + script + ") [WARN] [/color]","[color=orange][b]","[/b][/color]",["[color=orange]","[/color]"]) 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) print_rich(logmsg)
# Emit logevent signal
emit_signal("logevent","WARN",script,message,logmsg) emit_signal("logevent","WARN",script,message,logmsg)
else: else:
var logmsg = "[color=orange](" + script + ") [WARN] [b]" + message + "[/b][/color]" # Construct a log message normally if preprocessor is disabled/disallowed
print_rich(logmsg) # 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) emit_signal("logevent","WARN",script,message,logmsg)
func error(script:String,message:String,preproc:bool = true) -> void: func error(script:String,message:String,preproc:bool = true) -> void:
if enable: if core.protection_mode: return
if preproc and Preprocessor.enabled: # Check if the logger is enabled
var logmsg = preprocessor.process(message,"[color=red](" + script + ") [ERROR] [/color]","[color=red][b]","[/b][/color]",["[color=red]","[/color]"]) 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) print_rich(logmsg)
emit_signal("logevent","ERROR",script,message,logmsg) # Emit logevent signal
emit_signal("logevent","ERR!",script,message,logmsg)
else: else:
var logmsg = "[color=red](" + script + ") [ERROR] [b]" + message + "[/b][/color]" # Construct a log message normally if preprocessor is disabled/disallowed
print_rich(logmsg) # Note: We do not include bold and color tags in here because they can mess
emit_signal("logevent","ERROR",script,message,logmsg) # 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 - Home: index.md
- Licensing: licensing.md - Licensing: licensing.md
- Installing: install.md - Installing: install.md
- Updating: update.md - Quick Start Guide: quickstartguide.md
- Breaking commits: breaking-commits.md
- Troubleshooting: troubleshooting.md - Troubleshooting: troubleshooting.md
- References: references/ - References: references/
- Source code: https://git.staropensource.de/staropensource/core/ - 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 extends Node
@onready # CORE modules
var core = get_node("/root/core") var core: Node = null
var fsizes = {"text":"16","h1":"29","h2":"24","h3":"19","h4":"14","h5":"9","h6":"4"} 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: func parse(content:String) -> String:
var parse_text = "" var parse_text: String = ""
for line in content.split("\n",false): for line in content.split("\n",false):
var line_mod = line var line_mod: String = line
if line_mod.begins_with("######"): if line_mod.begins_with("######"):
line_mod = line_mod.replace("######","[font_size=" + fsizes["h6"] + "]") + "[/font_size]" line_mod = line_mod.replace("######","[font_size=" + fsizes["h6"] + "]") + "[/font_size]"
elif line_mod.begins_with("#####"): elif line_mod.begins_with("#####"):
@ -24,6 +38,3 @@ func parse(content:String) -> String:
line_mod = "[font_size=" + fsizes["text"] + "]" + line_mod + "[/font_size]" line_mod = "[font_size=" + fsizes["text"] + "]" + line_mod + "[/font_size]"
parse_text = parse_text + line_mod + "\n" parse_text = parse_text + line_mod + "\n"
return parse_text return parse_text
func initialize() -> void:
core.setready()

View file

@ -1,193 +1,60 @@
# preprocessor.gd ######################################
# CORE Text Preprocessor # THE CORE FRAMEWORK #
# # MADE BY THE STAROPENSOURCE PROJECT #
# This file is part of StarOpenSource CORE (SOSCORE) # AND CONTRIBUTERS (THANK YOU!) #
# Made by the StarOpenSource Project and Contributers # #
# Licensed under GNU GPLv3 # COPYRIGHT 2023 THE STAROPENSOURCE #
# # PROJECT AND CONTRIBUTERS #
# <tag> list/table: # #
# Tag | Description # LICENSED UNDER THE GNU GENERAL #
# <nl> | Newline (DO NOT USE '\n'!) # PUBLIC LICENSE VERSION 3 (ONLY) #
# <lo> | Text is lowercase until closing tag ######################################
# <up> | Text is UPPERCASE until closing tag extends Node
# <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>
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 # CORE modules
@export_category("Configuration") var core: Node = null
# Enables/disables Preprocessor. var logger: Node = null
# Enables/disables preprocessor functionality
@export var enabled = true @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. # Do not enable unless you exactly know what you are doing!
# Requires Logger.enable -> true # It will spam your log chock full of useless garbage!
@export var verbose_logging = false @export var diagnostic = 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
func _ready() -> void: # Checks if logger is null
print("preprocessor -> Initializing Preprocessor") func initialize() -> void:
print("preprocessor -> Delaying initialization by 0.75s") if core.protection_mode: return
await get_tree().create_timer(0.75).timeout if logger == null:
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)
return return
# If the Preprocessor is not enabled return logger.diag("CORE/preprocessor.gd","Preprocessor is ready.",false)
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)
# Processes <nl> tags # Parses <nl> tags
func _newline(msg:String,prefix:String,pre_msg:String,post_msg:String,exclusion_filter:Array) -> String: func _newline(msg:String,prefix:String,pre_msg:String,post_msg:String,exclusion_filter:Array) -> String:
if verbose_logging: if core.protection_mode: return ""
logger.diag("Preprocessor","Preprocessing newlines") if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing newline tags",false)
var prefix_space = prefix var prefix_space = prefix
for exclusion in exclusion_filter: for exclusion in exclusion_filter:
prefix_space = prefix_space.replace(exclusion,"") prefix_space = prefix_space.replace(exclusion,"")
prefix_space = " ".repeat(prefix_space.length()) prefix_space = " ".repeat(prefix_space.length())
var msg_proc = prefix + pre_msg + msg.replace("<nl>",post_msg + "\n" + prefix_space + pre_msg) + post_msg var msg_proc = prefix + pre_msg + msg.replace("<nl>",post_msg + "\n" + prefix_space + pre_msg) + post_msg
if verbose_logging: if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed newline tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
logger.diag("Preprocessor","Preprocessed newlines")
return msg_proc return msg_proc
# Processes <lo> and </lo> tags # Parses <lo> and </lo> tags
# Warning: Please do NOT modify the while true loop. It was a pain to debug, believe me.
func _case_lower(msg:String) -> String: func _case_lower(msg:String) -> String:
if verbose_logging: if core.protection_mode: return ""
logger.diag("Preprocessor","Preprocessing lowercasing") if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing lowercase tags",false)
var msg_proc = msg var msg_proc = msg
while true: while true:
var index_one = msg_proc.find("<lo>") 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) 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()) msg_proc = msg_proc.replace(index_proc,index_proc.replace("<lo>","").replace("</lo>","").to_lower())
else: 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 msg_proc = msg
break break
else: else:
break break
if verbose_logging: if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed lowercase tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
logger.diag("Preprocessor","Preprocessed lowercasing")
return msg_proc return msg_proc
# Processes <up> and </up> tags # Parses <up> and </up> tags
# Warning: Please do NOT modify the while true loop. It was a pain to debug, believe me.
func _case_upper(msg:String) -> String: func _case_upper(msg:String) -> String:
if verbose_logging: if core.protection_mode: return ""
logger.diag("Preprocessor","Preprocessing uppercasing") if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing uppercase tags",false)
var msg_proc = msg var msg_proc = msg
while true: while true:
var index_one = msg_proc.find("<up>") 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) 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()) msg_proc = msg_proc.replace(index_proc,index_proc.replace("<up>","").replace("</up>","").to_upper())
else: 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 msg_proc = msg
break break
else: else:
break break
if verbose_logging: if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed uppercase tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
logger.diag("Preprocessor","Preprocessed uppercasing")
return msg_proc return msg_proc
# Processes <ca> and </ca> tags # Parses <ca> and </ca> tags
# Warning: Please do NOT modify the while true loop. It was a pain to debug, believe me.
func _case_camelcase(msg:String) -> String: func _case_camelcase(msg:String) -> String:
if verbose_logging: if core.protection_mode: return ""
logger.diag("Preprocessor","Preprocessing camelcasing") if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing camelcase tags",false)
var msg_proc = msg var msg_proc = msg
while true: while true:
var index_one = msg_proc.find("<ca>") 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) 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()) msg_proc = msg_proc.replace(index_proc,index_proc.replace("<ca>","").replace("</ca>","").to_camel_case())
else: 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 msg_proc = msg
break break
else: else:
break break
if verbose_logging: if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed camelcase tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
logger.diag("Preprocessor","Preprocessed camelcasing")
return msg_proc return msg_proc
# Processes <pa> and </pa> tags # Parses <pa> and </pa> tags
# Warning: Please do NOT modify the while true loop. It was a pain to debug, believe me.
func _case_pascalcase(msg:String) -> String: func _case_pascalcase(msg:String) -> String:
if verbose_logging: if core.protection_mode: return ""
logger.diag("Preprocessor","Preprocessing pascalcasing") if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing pascalcase tags",false)
var msg_proc = msg var msg_proc = msg
while true: while true:
var index_one = msg_proc.find("<pa>") 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) 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()) msg_proc = msg_proc.replace(index_proc,index_proc.replace("<pa>","").replace("</pa>","").to_pascal_case())
else: 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 msg_proc = msg
break break
else: else:
break break
if verbose_logging: if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed pascalcase tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
logger.diag("Preprocessor","Preprocessed pascalcasing")
return msg_proc return msg_proc
# Processes <sn> and </sn> tags # Parses <sn> and </sn> tags
# Warning: Please do NOT modify the while true loop. It was a pain to debug, believe me.
func _case_snakecase(msg:String) -> String: func _case_snakecase(msg:String) -> String:
if verbose_logging: if core.protection_mode: return ""
logger.diag("Preprocessor","Preprocessing snakecasing") if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing snakecase tags",false)
var msg_proc = msg var msg_proc = msg
while true: while true:
var index_one = msg_proc.find("<sn>") 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) 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()) msg_proc = msg_proc.replace(index_proc,index_proc.replace("<sn>","").replace("</sn>","").to_snake_case())
else: 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 msg_proc = msg
break break
else: else:
break break
if verbose_logging: if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed snakecase tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
logger.diag("Preprocessor","Preprocessed snakecasing")
return msg_proc return msg_proc
# Functions to call all other functions related to *case # Function calls to everything *case-related
func _case(msg:String) -> String: func _case(msg:String) -> String:
if verbose_logging: if core.protection_mode: return ""
logger.diag("Preprocessor","Preprocessing casing") if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing casing tags",false)
var msg_proc = _case_lower(msg) var msg_proc = _case_lower(msg)
msg_proc = _case_upper(msg_proc) msg_proc = _case_upper(msg_proc)
msg_proc = _case_camelcase(msg_proc) msg_proc = _case_camelcase(msg_proc)
msg_proc = _case_pascalcase(msg_proc) msg_proc = _case_pascalcase(msg_proc)
msg_proc = _case_snakecase(msg_proc) msg_proc = _case_snakecase(msg_proc)
if verbose_logging: if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed casing tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
logger.diag("Preprocessor","Preprocessed casing")
return msg_proc return msg_proc
# Replaces all escapes # Replaces all escapes
func _escapes(msg:String) -> String: func _escapes(msg:String) -> String:
if verbose_logging: if core.protection_mode: return ""
logger.diag("Preprocessor","Preprocessing escapes") if diagnostic:logger.diag("CORE/preprocessor.gd","Parsing escape tags",false)
var msg_proc = msg.replace("<esc_nl>","<nl>") var msg_proc = msg.replace("<esc_nl>","<nl>")
msg_proc = msg_proc.replace("<esc_up>","<up>") msg_proc = msg_proc.replace("<esc_up>","<up>")
msg_proc = msg_proc.replace("<esc_lo>","<lo>") 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_pa>","</pa>")
msg_proc = msg_proc.replace("</esc_sn>","</sn>") msg_proc = msg_proc.replace("</esc_sn>","</sn>")
msg_proc = msg_proc.replace("<esc_np>","<np>") msg_proc = msg_proc.replace("<esc_np>","<np>")
if verbose_logging: if diagnostic: logger.diag("CORE/preprocessor.gd","Parsed escape tags. Transformed \"" + msg + "\" into \"" + msg_proc + "\"",false)
logger.diag("Preprocessor","Preprocessed escapes")
return msg_proc 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: func _noprocess(msg:String) -> bool:
if verbose_logging: if core.protection_mode: return true
logger.diag("Preprocessor","Preprocessing noprocess") if diagnostic: logger.diag("CORE/preprocessor.gd","Checking for noprocess tag", false)
if msg.contains("<np>"): if msg.contains("<np>"):
return true return true
return false return false
# Executes all preprocessing functions and returns their combined work # 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: func process(msg:String,prefix:String = "",pre_msg:String = "",post_msg:String = "",exclusion_filter:Array = []) -> String:
if verbose_logging: if core.protection_mode: return ""
logger.diag("Preprocessor","Preprocessing a message") if diagnostic: logger.diag("CORE/preprocessor.gd","Call to process() recieved",false)
if !enabled: if !enabled:
if verbose_logging: if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing failed: Preprocessor is disabled",false)
logger.diag("Preprocessor","Preprocessing failed: Preprocessor is disabled")
return msg return msg
if _noprocess(msg): if _noprocess(msg):
if verbose_logging: if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing stopped: noprocess tag detected", false)
logger.diag("Preprocessor","Preprocessing cancelled: <np> tag detected")
return msg return msg
var msg_proc = _case(msg) var msg_proc = _case(msg)
msg_proc = _newline(msg_proc,prefix,pre_msg,post_msg,exclusion_filter) msg_proc = _newline(msg_proc,prefix,pre_msg,post_msg,exclusion_filter)
msg_proc = _escapes(msg_proc) msg_proc = _escapes(msg_proc)
if verbose_logging: if diagnostic: logger.diag("CORE/preprocessor.gd","Parsing complete", false)
logger.diag("Preprocessor","Preprocessing complete")
return msg_proc return msg_proc

111
resmgr.gd
View file

@ -1,53 +1,94 @@
# resmgr.gd ######################################
# Resource Manager # THE CORE FRAMEWORK #
# # MADE BY THE STAROPENSOURCE PROJECT #
# This file is part of StarOpenSource CORE (SOSCORE) # AND CONTRIBUTERS (THANK YOU!) #
# Made by the StarOpenSource Project and Contributers # #
# Licensed under GNU GPLv3 # COPYRIGHT 2023 THE STAROPENSOURCE #
# PROJECT AND CONTRIBUTERS #
# #
# LICENSED UNDER THE GNU GENERAL #
# PUBLIC LICENSE VERSION 3 (ONLY) #
######################################
extends Node extends Node
@onready # CORE modules
var core = get_node(NodePath("/root/core")) var core: Node = null
var resources = {} var logger: Node = null
func initialize() -> void: # Loaded resources list
if core.protection_mode: return var resources: Dictionary = {}
core.setready()
func loadres(resname:String,respath:String,replace:bool = false) -> void: # Config
if core.protection_mode: return var config_load_invalid_file_as_null: bool = false
if resources.has(resname):
# 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: 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: else:
Logger.error("resmgr","Loading \"" + resname + "\" failed: Resource is loaded already") # If resource is already loaded and replace is false, throw an error
return var err = core.error("ResourceManager",core.Errors.RESOURCEMANAGER_ALREADY_EXISTS,{"name":resource_name})
resources.merge({resname:ResourceLoader.load(respath)}) 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: # Unloads a resource
if core.protection_mode: return func unloadres(resource_name:String) -> int:
if !resources.has(resname): if core.protection_mode: return 9223372036854775807
Logger.error("resmgr","Unloading \"" + resname + "\" failed: Resource is not present") if !resources.has(resource_name):
return # If resource is not loaded, throw an error
resources.erase(resname) 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: # Loads a batch of resources
if core.protection_mode: return func loadbatch(batch:Dictionary,replace:bool = false) -> int:
if core.protection_mode: return 9223372036854775807
if batch == {}: 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: for i in batch:
# Call loadres() method for every item in batch
loadres(i,batch[i],replace) loadres(i,batch[i],replace)
return core.Errors.OK
func unloadbatch(batch:Array) -> void: # Unloads a batch of resources
if core.protection_mode: return func unloadbatch(batch:Array) -> int:
if core.protection_mode: return 9223372036854775807
if batch == []: 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: for i in batch:
# Call unloadres() method for every item in batch
unloadres(i) unloadres(i)
return core.Errors.OK
# No set return type here as it can return literally everything. # Returns a loaded resource
func getres(resname:String): # No return type is set because it can return literally everything.
func getres(resource_name:String):
if core.protection_mode: return null 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 null
return resources[resname] # Return the content
return resources[resource_name]

304
smgr.gd
View file

@ -1,169 +1,153 @@
# smgr.gd ######################################
# Scene Manager # THE CORE FRAMEWORK #
# # MADE BY THE STAROPENSOURCE PROJECT #
# This file is part of StarOpenSource CORE (SOSCORE) # AND CONTRIBUTERS (THANK YOU!) #
# Made by the StarOpenSource Project and Contributers # #
# Licensed under GNU GPLv3 # COPYRIGHT 2023 THE STAROPENSOURCE #
# PROJECT AND CONTRIBUTERS #
# #
# LICENSED UNDER THE GNU GENERAL #
# PUBLIC LICENSE VERSION 3 (ONLY) #
######################################
extends Node extends Node
@onready # CORE modules
var core = get_node(NodePath("/root/core")) var core: Node = null
var ccr = null var logger: Node = null
var ccr_game = null var resourcemanager: Node = 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 = []
# 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: func initialize() -> void:
if core.protection_mode: return if core.protection_mode: return
Logger.diag("smgr","Constructing CORE Scene Root (CCR)") logger.diag("CORE/smgr.gd","Constructing overlays")
ccr = Control.new() # Set overlay names
ccr.name = "ccr" debug_overlay.name = "DebugOverlay"
Logger.diag("smgr","Adding CCR to /root/") cutscene_overlay.name = "CutsceneOverlay"
get_tree().root.add_child(ccr) menu_overlay.name = "MenuOverlay"
Logger.diag("smgr","Migrating COREBackground to CCR") action_overlay.name = "ActionOverlay"
var corebg = get_tree().current_scene logger.diag("CORE/smgr.gd","Adding overlays")
Logger.diag("smgr","Reconstructing COREBackground to CCR") # Adds overlays to /root/
var corebg_log = corebg.get_node(NodePath("Background/Log")).text get_tree().root.add_child(debug_overlay)
corebg.get_node(NodePath("Background/Log")).rmconnect() get_tree().root.add_child(cutscene_overlay)
get_tree().current_scene.queue_free() get_tree().root.add_child(menu_overlay)
var corebg_new = ResourceLoader.load("res://CORE/background.tscn").instantiate() get_tree().root.add_child(action_overlay)
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()
func add_game(resname:String) -> bool: # Adds a debug scene
if core.protection_mode: return false func add_debug(resource_name:String) -> int:
Logger.diag("smgr","Adding game scene") if core.protection_mode: return core.Errors.CORE_PROTECTIONMODE
if ccr_game_inuse: logger.diag("CORE/smgr.gd","Adding debug scene \"" + resource_name + "\"")
Logger.error("smgr","Failed adding game scene: Only one game scene is allowed") # Load resource into memory
return false var resource: Object = resourcemanager.getres(resource_name)
var res = core.resmgr.getres(resname) if resource == null or resource.get_class() != "PackedScene":
if res == null or res.get_class() != "PackedScene": # If resource is null (not loaded) or is not a PackedScene, throw an error
Logger.error("smgr","Resource is not type of PackedScene") var err = core.error("SceneManager",core.Errors.SCENEMANAGER_NOT_PACKEDSCENE,{"scene":resource_name,"overlay":"debug"})
return false logger.error("CORE/smgr.gd",err["error"])
ccr_game.add_child(res.instantiate()) return err["code"]
ccr_game_inuse = true if debug_overlay_scene.has(resource_name) and debug_overlay.get_children().has(resource):
Logger.diag("smgr","Added game scene") # If scene already exists, throw an error
return true 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: # Adds a menu scene
if core.protection_mode: return false func add_menu(resource_name:String) -> int:
Logger.diag("smgr","Removing game scene") if core.protection_mode: return core.Errors.CORE_PROTECTIONMODE
if !ccr_game_inuse: logger.diag("CORE/smgr.gd","Adding menu scene \"" + resource_name + "\"")
Logger.error("smgr","Failed removing game scene: No game scene is active") # Load resource into memory
return false var resource: Object = resourcemanager.getres(resource_name)
ccr_game.remove_child(ccr_game.get_child(0)) if resource == null or resource.get_class() != "PackedScene":
ccr_game_inuse = false # If resource is null (not loaded) or is not a PackedScene, throw an error
Logger.diag("smgr","Removed game scene") var err = core.error("SceneManager",core.Errors.SCENEMANAGER_NOT_PACKEDSCENE,{"scene":resource_name,"overlay":"menu"})
return true 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: # Adds a cutscene scene
if core.protection_mode: return false func add_cutscene(resource_name:String) -> int:
Logger.diag("smgr","Adding menu scene \"" + resname + "\"") if core.protection_mode: return core.Errors.CORE_PROTECTIONMODE
if ccr_menu_names.has(resname): logger.diag("CORE/smgr.gd","Adding cutscene scene \"" + resource_name + "\"")
Logger.error("smgr","Failed adding menu scene: Menu scene with name \"" + resname + "\" already exists") # Load resource into memory
return false var resource: Object = resourcemanager.getres(resource_name)
var res = core.resmgr.getres(resname) if resource == null or resource.get_class() != "PackedScene":
if res == null or res.get_class() != "PackedScene": # If resource is null (not loaded) or is not a PackedScene, throw an error
Logger.error("smgr","Resource is not type of PackedScene") var err = core.error("SceneManager",core.Errors.SCENEMANAGER_NOT_PACKEDSCENE,{"scene":resource_name,"overlay":"cutscene"})
return false logger.error("CORE/smgr.gd",err["error"])
ccr_menu.add_child(res.instantiate()) return err["code"]
ccr_menu_names.append(resname) if cutscene_overlay_scene == resource_name and cutscene_overlay.get_children().has(resource):
Logger.diag("smgr","Added menu scene \"" + resname + "\"") # If resource is null (not loaded) or is not a PackedScene, throw an error
return true 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: # Adds a action scene
if core.protection_mode: return false func add_action(resource_name:String) -> int:
Logger.diag("smgr","Removing menu scene \"" + scene_name + "\"") if core.protection_mode: return core.Errors.CORE_PROTECTIONMODE
if !ccr_menu_names.has(scene_name): logger.diag("CORE/smgr.gd","Adding action scene \"" + resource_name + "\"")
Logger.error("smgr","Failed removing menu scene: Menu scene with name \"" + scene_name + "\" does not exist") # Load resource into memory
return false var resource = resourcemanager.getres(resource_name)
for i in ccr_menu.get_children(): if resource == null or typeof(resource) != TYPE_OBJECT or resource.get_class() != "PackedScene":
if i.name == scene_name: # If resource is null (not loaded) or is not a PackedScene, throw an error
ccr_menu.remove_child(i) var err = core.error("SceneManager",core.Errors.SCENEMANAGER_NOT_PACKEDSCENE,{"scene":resource_name,"overlay":"action"})
break logger.error("CORE/smgr.gd",err["error"])
ccr_menu_names.erase(scene_name) return err["code"]
Logger.diag("smgr","Removed menu scene \"" + scene_name + "\"") if action_overlay_scene == resource_name and action_overlay.get_children().has(resource):
return true # 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"})
func add_cutscene(resname:String) -> bool: logger.error("CORE/smgr.gd",err["error"])
if core.protection_mode: return false return err["code"]
Logger.diag("smgr","Adding cutscene scene") if action_overlay_scene != resource_name and action_overlay.get_children().has(resource):
if ccr_cutscene_inuse: core.exception("SceneManager","action_overlay_scene does not contain \"" + resource_name + "\" but action_overlay does")
Logger.error("smgr","Failed adding cutscene scene: Only one cutscene scene is allowed") return core.Errors.CORE_EXCEPTION
return false if action_overlay_scene == resource_name and !action_overlay.get_children().has(resource):
var res = core.resmgr.getres(resname) core.exception("SceneManager","action_overlay does not contain \"" + resource_name + "\" but action_overlay_scene does")
if res == null or res.get_class() != "PackedScene": return core.Errors.CORE_EXCEPTION
Logger.error("smgr","Resource is not type of PackedScene") action_overlay.add_child(resource)
return false action_overlay_scene = resource_name
ccr_cutscene.add_child(res.instantiate()) return core.Errors.OK
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)

View file

@ -1,48 +1,45 @@
# splash.gd ######################################
# Splash screen # THE CORE FRAMEWORK #
# # MADE BY THE STAROPENSOURCE PROJECT #
# This file is part of StarOpenSource CORE (SOSCORE) # AND CONTRIBUTERS (THANK YOU!) #
# Made by the StarOpenSource Project and Contributers # #
# Licensed under GNU GPLv3 # COPYRIGHT 2023 THE STAROPENSOURCE #
# PROJECT AND CONTRIBUTERS #
# #
# LICENSED UNDER THE GNU GENERAL #
# PUBLIC LICENSE VERSION 3 (ONLY) #
######################################
extends Node extends Node
@onready # CORE modules
var core = get_node("/root/core") var core = null
var logger = null
# Config
var config_enabled = null var config_enabled = null
var config_image = null var config_image = null
var config_image_size = null var config_image_size = null
var config_color = null var config_color = null
func load_configuration() -> void: # Makes the splash screen pretty
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()
func apply_config() -> void: func apply_config() -> void:
if core.protection_mode: return if core.protection_mode: return
$Background.color = config_color $Background.color = config_color
$Background/Image.texture = ResourceLoader.load(config_image) $Background/Image.texture = ResourceLoader.load(config_image)
$Background/Image.size = Vector2i(config_image_size,config_image_size) $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: func display() -> void:
if core.protection_mode: return if core.protection_mode: return
Logger.info("splash","Displaying splash screen") logger.info("CORE/splash.gd","Displaying splash screen")
get_tree().root.move_child($"/root/ccr",0) get_tree().root.move_child($"/root/CORE/",0)
$Background.visible = true $Background.visible = true
func dissolve() -> void: func dissolve() -> void:
if core.protection_mode: return if core.protection_mode: return
Logger.info("splash","Dissolving splash screen") logger.info("CORE/splash.gd","Dissolving splash screen")
$Background.visible = false $Background.visible = false

View file

@ -3,7 +3,7 @@
[ext_resource type="Script" path="res://CORE/splash.gd" id="1_n4sar"] [ext_resource type="Script" path="res://CORE/splash.gd" id="1_n4sar"]
[ext_resource type="Texture2D" path="res://CORE/soscore.png" id="2_5krj5"] [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 layout_mode = 3
anchors_preset = 15 anchors_preset = 15
anchor_right = 1.0 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