diff --git a/README.md b/README.md
index 43c17cf..2c8c921 100644
--- a/README.md
+++ b/README.md
@@ -1,38 +1,46 @@
-# StarOpenSource CORE (aka. SOSCORE aka. CORE) [![Please don't upload to GitHub](https://nogithub.codeberg.page/badge.svg)](https://nogithub.codeberg.page)
+
+# StarOpenSource CORE (aka. SOSCORE aka. CORE)
SOSCORE/CORE is a framework that simplifies development for games and applications made in Godot 4.
# Development status
-CORE is not yet ready for production as it is in rapid development. Only use it in temporary/testing projects for now.
+CORE is under heavy development and can be very unstable. Please do not use CORE in conjunction with your game/application for now (except if you want to debug your game 24/7 and read a lot of gdscript files).
+
+# Roadmap to release
+- Mod loading system
+- Notification API
+- Basic debugging tool (CTRL+C to crash, F3 to toggle statistics)
+- Better documentation (docs4everything)
+- Everything commented and explained
+- Documentation page explaining what does what (for CORE noobies)
+- Autoload singleton check removal
+- More wmgr functions
+- Website
# Documentaton
-[You can access the documentation by clicking this text.](https://git.staropensource.de/StarOpenSource/core/wiki)
+[You can access the documentation by clicking this text](https://git.staropensource.de/StarOpenSource/core/wiki)[.](https://takeb1nzyto.space)
-# For whom is it useful?
-CORE is only useful for new projects. Already existing projects could break because CORE has certain requirements that must be met.
+# Can I use CORE in an existing project?
+Yes, in theory you can refactor your entire codebase and make a giant mess, but we don't recommend doing that.
# Requirements
-- Godot 4.0 (only stable releases)
-- No autoload singletons are allowed before CORE has initialized
-- Startup scene must be `res://CORE/coreinit.tscn`
-- Scene management must be done with smgr (the CORE scene manager)
-- Logging should be handled using the CORE logger
+- Godot 4.0/4.1 (stable releases only)
+- Good experience with Godot 4 and GDScript
+
+# Recommendations
+- Use smgr instead of manually managing scenes or CORE will break apart. If you don't want headaches, use smgr.
+- Use the CORE logger for logging. It supports rich formatting (using tags, handled by our Preprocessor™) and is generally better than using print() for everything.
+- Use wmgr for managing the main window title, size, position, etc.
# How to install
-- Clone CORE into your project root using `git clone https://git.staropensource.de/StarOpenSource/core.git CORE` \
- **NOTE:** Please execute `git submodule init` and then `git submodule add https://git.staropensource.de/staropensource/core.git CORE` instead if you are using a git repository for your app/game already.
-- Remove any autoload singletons
-- Add three scripts to your autoload:
-| Name | Path |
-| ------------ | ---------------------------- |
-| Logger | `res://CORE/logger.gd` |
-| Preprocessor | `res://CORE/preprocessor.gd` |
-- Select `res://CORE/coreinit.tscn` as your startup scene
-- Duplicate `config.gd.example` and name it `config.gd`
-- [Follow the post-installation guide](https://git.staropensource.de/StarOpenSource/core/wiki/Using-CORE)
+- Download the [CORE manager](https://git.staropensource.de/StarOpenSource/core-manager#download) and open it
+- Enter the path to your Godot project
+- Click `Install` and wait 0-2 seconds for it to download
+- Reload your project (`Project -> Reload current project`) and start your game
+- If Godot complains that it could not load `res://`, then you successfully installed CORE. [You can now follow the post install guide](https://git.staropensource.de/StarOpenSource/core/wiki/Using-CORE)
# How to update
-- Close your project
-- Pull new changes using `git pull`
-- [Check for commits that break things](https://git.staropensource.de/StarOpenSource/core/wiki/Updating-CORE)
-- Reopen your project
+Open the CORE manager, enter the path to your Godot project and click `Update`. Check [this documentation page](https://git.staropensource.de/StarOpenSource/core/wiki/Breaking-commits) for important commits that can cause breakage.
+
+# Why is CORE not a addon?
+CORE does not add one single functionality that can be easily removed, no, it is a whole framework providing many useful functions for your game and removing it would mean lots of refactoring and headaches for you. So no, no addon.
\ No newline at end of file
diff --git a/logger.gd b/logger.gd
index cdfccb6..ee54859 100644
--- a/logger.gd
+++ b/logger.gd
@@ -31,7 +31,7 @@ func _ready() -> void:
func diag(script:String,message:String,preproc:bool = false) -> void:
if enable and enable_diag:
if preproc and Preprocessor.enabled:
- var logmsg = "[color=gray](" + script + ") [DIAG] [b]" + preprocessor.pre(0,script,message) + "[/b][/color]"
+ var logmsg = preprocessor.process(message,"[color=gray](" + script + ") [DIAG] [/color]","[color=gray][b]","[/b][/color]",["[color=gray]","[/color]"])
print_rich(logmsg)
emit_signal("logevent","DIAG",script,message,logmsg)
else:
@@ -42,7 +42,7 @@ func diag(script:String,message:String,preproc:bool = false) -> void:
func info(script:String,message:String,preproc:bool = true) -> void:
if enable:
if preproc and Preprocessor.enabled:
- var logmsg = "(" + script + ") [INFO] [b]" + preprocessor.pre(1,script,message) + "[/b]"
+ var logmsg = preprocessor.process(message,"[color=white](" + script + ") [INFO] [/color]","[color=white][b]","[/b][/color]",["[color=white]","[/color]"])
print_rich(logmsg)
emit_signal("logevent","INFO",script,message,logmsg)
else:
@@ -53,7 +53,7 @@ func info(script:String,message:String,preproc:bool = true) -> void:
func warn(script:String,message:String,preproc:bool = true) -> void:
if enable:
if preproc and Preprocessor.enabled:
- var logmsg = "[color=orange](" + script + ") [WARN] [b]" + preprocessor.pre(2,script,message) + "[/b][/color]"
+ var logmsg = preprocessor.process(message,"[color=orange](" + script + ") [WARN] [/color]","[color=orange][b]","[/b][/color]",["[color=orange]","[/color]"])
print_rich(logmsg)
emit_signal("logevent","WARN",script,message,logmsg)
else:
@@ -64,7 +64,7 @@ func warn(script:String,message:String,preproc:bool = true) -> void:
func error(script:String,message:String,preproc:bool = true) -> void:
if enable:
if preproc and Preprocessor.enabled:
- var logmsg = "[color=red](" + script + ") [ERROR] [b]" + preprocessor.pre(3,script,message) + "[/b][/color]"
+ var logmsg = preprocessor.process(message,"[color=red](" + script + ") [ERROR] [/color]","[color=red][b]","[/b][/color]",["[color=red]","[/color]"])
print_rich(logmsg)
emit_signal("logevent","ERROR",script,message,logmsg)
else:
diff --git a/preprocessor.gd b/preprocessor.gd
index 94f7590..20549f7 100644
--- a/preprocessor.gd
+++ b/preprocessor.gd
@@ -31,6 +31,11 @@ var logger = null
# 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
@@ -52,19 +57,17 @@ func _ready() -> void:
# 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.info("Preprocessor","Testing preprocessor...",false)
# If tests are disaled and ignore_flag is false return
if !tests_enabled and !ignore_flag:
- logger.info("Preprocessor","Testing Preprocessor [❌]: Preprocessor testing is disabled. To test the Preprocessor manually, execute this in your script:",false)
- logger.info("Preprocessor"," get_node(NodePath(\"/root/Preprocessor\")).do_tests(true)",false)
+ logger.info("Preprocessor","Testing failed: Tests are disabled.",false)
return
# If the Preprocessor is not enabled return
if !enabled:
- logger.info("Preprocessor","Testing Preprocessor [❌]: Preprocessor is disabled. To enable the Preprocessor and test it, execute this:",false)
- logger.info("Preprocessor"," get_node(NodePath(\"/root/Preprocessor\")).enabled = true",false)
- logger.info("Preprocessor"," get_node(NodePath(\"/root/Preprocessor\")).do_tests(true)",false)
+ logger.info("Preprocessor","Testing failed: Preprocessor is disabled.",false)
return
# Expected test resulsts
- var tests_newlines = "\n(Preprocessor) Newline 1\n(Preprocessor) Newline 2"
+ 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"
@@ -77,102 +80,105 @@ func do_tests(ignore_flag:bool = false) -> void:
var tests_escapes_pascalcase = ""
var tests_escapes_snakecase = ""
# Actual tests performed using pre()
- var tests_newlines_result = pre(1,"Preprocessor","Newline 1Newline 2")
- var tests_uppercase_result = pre(1,"Preprocessor","a ThIs tExT sHoUlD bE uPpPeRcAsEd b")
- var tests_lowercase_result = pre(1,"Preprocessor","a ThIs tExT sHoUlD bE lOwErCaSeD b")
- var tests_camelcase_result = pre(1,"Preprocessor","a thisShould_be_camel_CASEd b")
- var tests_pascalcase_result = pre(1,"Preprocessor","a thisShould_be_pascal_CASEd b")
- var tests_snakecase_result = pre(1,"Preprocessor","a thisShould_be_snake_CASEd b")
- var tests_escapes_newlines_result = pre(1,"Prepreprocessor","")
- var tests_escapes_uppercase_result = pre(1,"Prepreprocessor","")
- var tests_escapes_lowercase_result = pre(1,"Prepreprocessor","")
- var tests_escapes_camelcase_result = pre(1,"Prepreprocessor","")
- var tests_escapes_pascalcase_result = pre(1,"Prepreprocessor","")
- var tests_escapes_snakecase_result = pre(1,"Prepreprocessor","")
+ var tests_newlines_result = process("Line 1Line 2Line 3","test_prefix","_",".")
+ var tests_uppercase_result = process("a ThIs tExT sHoUlD bE uPpPeRcAsEd b")
+ var tests_lowercase_result = process("a ThIs tExT sHoUlD bE lOwErCaSeD b")
+ var tests_camelcase_result = process("a thisShould_be_camel_CASEd b")
+ var tests_pascalcase_result = process("a thisShould_be_pascal_CASEd b")
+ var tests_snakecase_result = process("a thisShould_be_snake_CASEd b")
+ var tests_escapes_newlines_result = process("")
+ var tests_escapes_uppercase_result = process("")
+ var tests_escapes_lowercase_result = process("")
+ var tests_escapes_camelcase_result = process("")
+ var tests_escapes_pascalcase_result = process("")
+ var tests_escapes_snakecase_result = process("")
# 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 = "✔️ Test NEWLINES returned \"" + tests_newlines_result + "\".\n"
+ tests_log = "Y Test NEWLINES returned:\n" + tests_newlines_result + "\n"
else:
- tests_log = "❌ Test NEWLINES returned \"" + tests_newlines_result + "\" instead of \"" + tests_newlines + "\".\n"
+ 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 + "✔️ Test UPPERCASE returned \"" + tests_uppercase_result + "\".\n"
+ tests_log = tests_log + "Y Test UPPERCASE returned \"" + tests_uppercase_result + "\".\n"
else:
- tests_log = tests_log + "❌ Test UPPERCASE returned \"" + tests_uppercase_result + "\" instead of \".\n" + tests_uppercase + "\".\n"
+ tests_log = tests_log + "N Test UPPERCASE returned \"" + tests_uppercase_result + "\" instead of \"\n" + tests_uppercase + "\".\n"
if tests_lowercase_result == tests_lowercase:
tests_success = tests_success+1
- tests_log = tests_log + "✔️ Test LOWERCASE returned \"" + tests_lowercase_result + "\".\n"
+ tests_log = tests_log + "Y Test LOWERCASE returned \"" + tests_lowercase_result + "\".\n"
else:
- tests_log = tests_log + "❌ Test LOWERCASE returned \"" + tests_lowercase_result + "\" instead of \".\n" + tests_lowercase + "\".\n"
+ tests_log = tests_log + "N Test LOWERCASE returned \"" + tests_lowercase_result + "\" instead of \"\n" + tests_lowercase + "\".\n"
if tests_camelcase_result == tests_camelcase:
tests_success = tests_success+1
- tests_log = tests_log + "✔️ Test CAMELCASE returned \"" + tests_camelcase_result + "\".\n"
+ tests_log = tests_log + "Y Test CAMELCASE returned \"" + tests_camelcase_result + "\".\n"
else:
- tests_log = tests_log + "❌ Test CAMELCASE returned \"" + tests_camelcase_result + "\" instead of \".\n" + tests_camelcase + "\".\n"
+ tests_log = tests_log + "N Test CAMELCASE returned \"" + tests_camelcase_result + "\" instead of \"\n" + tests_camelcase + "\".\n"
if tests_pascalcase_result == tests_pascalcase:
tests_success = tests_success+1
- tests_log = tests_log + "✔️ Test PASCALCASE returned \"" + tests_pascalcase_result + "\".\n"
+ tests_log = tests_log + "Y Test PASCALCASE returned \"" + tests_pascalcase_result + "\".\n"
else:
- tests_log = tests_log + "❌ Test PASCALCASE returned \"" + tests_pascalcase_result + "\" instead of \".\n" + tests_pascalcase + "\".\n"
+ tests_log = tests_log + "N Test PASCALCASE returned \"" + tests_pascalcase_result + "\" instead of \"\n" + tests_pascalcase + "\".\n"
if tests_snakecase_result == tests_snakecase:
tests_success = tests_success+1
- tests_log = tests_log + "✔️ Test SNAKECASE returned \"" + tests_snakecase_result + "\".\n"
+ tests_log = tests_log + "Y Test SNAKECASE returned \"" + tests_snakecase_result + "\".\n"
else:
- tests_log = tests_log + "❌ Test SNAKECASE returned \"" + tests_snakecase_result + "\" instead of \".\n" + tests_snakecase + "\".\n"
+ tests_log = tests_log + "N Test SNAKECASE returned \"" + tests_snakecase_result + "\" instead of \"\n" + tests_snakecase + "\".\n"
if tests_escapes_newlines_result == tests_escapes_newlines:
tests_success = tests_success+1
- tests_log = tests_log + "✔️ Test ESCAPES_NEWLINES returned \"" + tests_escapes_newlines_result + "\".\n"
+ tests_log = tests_log + "Y Test ESCAPES_NEWLINES returned \"" + tests_escapes_newlines_result + "\".\n"
else:
- tests_log = tests_log + "❌ Test ESCAPES_NEWLINES returned \"" + tests_escapes_newlines_result + "\" instead of \"" + tests_escapes_newlines + "\".\n"
+ 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 + "✔️ Test ESCAPES_UPPERCASE returned \"" + tests_escapes_uppercase_result + "\".\n"
+ tests_log = tests_log + "Y Test ESCAPES_UPPERCASE returned \"" + tests_escapes_uppercase_result + "\".\n"
else:
- tests_log = tests_log + "❌ Test ESCAPES_UPPERCASE returned \"" + tests_escapes_uppercase_result + "\" instead of \"" + tests_escapes_uppercase + "\".\n"
+ 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 + "✔️ Test ESCAPES_LOWERCASE returned \"" + tests_escapes_lowercase_result + "\".\n"
+ tests_log = tests_log + "Y Test ESCAPES_LOWERCASE returned \"" + tests_escapes_lowercase_result + "\".\n"
else:
- tests_log = tests_log + "❌ Test ESCAPES_LOWERCASE returned \"" + tests_escapes_lowercase_result + "\" instead of \"" + tests_escapes_lowercase + "\".\n"
+ 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 + "✔️ Test ESCAPES_CAMELCASE returned \"" + tests_escapes_camelcase_result + "\".\n"
+ tests_log = tests_log + "Y Test ESCAPES_CAMELCASE returned \"" + tests_escapes_camelcase_result + "\".\n"
else:
- tests_log = tests_log + "❌ Test ESCAPES_CAMELCASE returned \"" + tests_escapes_camelcase_result + "\" instead of \"" + tests_escapes_camelcase + "\".\n"
+ 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 + "✔️ Test ESCAPES_PASCALCASE returned \"" + tests_escapes_pascalcase_result + "\".\n"
+ tests_log = tests_log + "Y Test ESCAPES_PASCALCASE returned \"" + tests_escapes_pascalcase_result + "\".\n"
else:
- tests_log = tests_log + "❌ Test ESCAPES_PASCALCASE returned \"" + tests_escapes_pascalcase_result + "\" instead of \"" + tests_escapes_pascalcase + "\".\n"
+ 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 + "✔️ Test ESCAPES_SNAKECASE returned \"" + tests_escapes_snakecase_result + "\".\n"
+ tests_log = tests_log + "Y Test ESCAPES_SNAKECASE returned \"" + tests_escapes_snakecase_result + "\".\n"
else:
- tests_log = tests_log + "❌ Test ESCAPES_SNAKECASE returned \"" + tests_escapes_snakecase_result + "\" instead of \"." + tests_escapes_snakecase + "\".\n"
+ 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.info("Preprocessor","Testing Preprocessor [✔️]: All Preprocessor features are working.",false)
+ logger.info("Preprocessor","Testing complete: All preprocessor features are working as intended.",false)
+ if tests_level == 2:
+ logger.info("Preprocessor","Log:\n" + tests_log)
else:
enabled = false
- logger.info("Preprocessor","Testing Preprocessor [❌]: Preprocessor is malfunctioning, Preprocessor is now disabled. Log:\n" + tests_log,false)
+ logger.info("Preprocessor","Testing failed: Preprocessor is malfunctioning and is now disabled.",false)
+ if tests_level >= 1:
+ logger.info("Preprocessor","Log:\n" + tests_log)
# Processes tags
-func _newline(type:int,script:String,msg:String) -> String:
+func _newline(msg:String,prefix:String,pre_msg:String,post_msg:String,exclusion_filter:Array) -> String:
if verbose_logging:
logger.diag("Preprocessor","Preprocessing newlines")
- var type_proc = ""
- if type == 3:
- type_proc = " "
- else:
- type_proc = " "
- var msg_proc = msg.replace("","\n(" + script + ") " + type_proc + " ")
+ var prefix_space = prefix
+ for exclusion in exclusion_filter:
+ prefix_space = prefix_space.replace(exclusion,"")
+ prefix_space = " ".repeat(prefix_space.length())
+ var msg_proc = prefix + pre_msg + msg.replace("",post_msg + "\n" + prefix_space + pre_msg) + post_msg
if verbose_logging:
logger.diag("Preprocessor","Preprocessed newlines")
return msg_proc
@@ -337,9 +343,9 @@ func _noprocess(msg:String) -> String:
return msg
# Executes all preprocessing functions and returns their combined work
-func pre(type:int,script:String,msg:String) -> String:
+func process(msg:String,prefix:String = "",pre_msg:String = "",post_msg:String = "",exclusion_filter:Array = []) -> String:
if verbose_logging:
- logger.diag("Preprocessor","Preprocessing a message with type \"" + str(type) + "\" from script \"" + script + "\"")
+ logger.diag("Preprocessor","Preprocessing a message")
if !enabled:
if verbose_logging:
logger.diag("Preprocessor","Preprocessing failed: Preprocessor is disabled")
@@ -350,8 +356,8 @@ func pre(type:int,script:String,msg:String) -> String:
if verbose_logging:
logger.diag("Preprocessor","Preprocessing cancelled: tag detected")
return msg_proc
- msg_proc = _newline(type,script,msg)
- msg_proc = _case(msg_proc)
+ msg_proc = _case(msg)
+ msg_proc = _newline(msg_proc,prefix,pre_msg,post_msg,exclusion_filter)
msg_proc = _escapes(msg_proc)
if verbose_logging:
logger.diag("Preprocessor","Preprocessing complete")