Improve README, logger and preprocessor (a lot)

This commit is contained in:
JeremyStar™ 2023-07-07 04:10:53 +02:00
parent 1635e98a4c
commit e4094e1aa1
3 changed files with 98 additions and 84 deletions

View file

@ -1,38 +1,46 @@
<p align=center><img width=200px height=200px src="https://git.staropensource.de/staropensource/core/raw/branch/develop/soscore.png"/></p>
# 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 <img width=32 src="https://net.staropensource.de/system/custom_emojis/images/000/009/330/static/a87bdcca6bcbb86e.png">
- 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.

View file

@ -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:

View file

@ -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 = "<pa></pa>"
var tests_escapes_snakecase = "<sn></sn>"
# Actual tests performed using pre()
var tests_newlines_result = pre(1,"Preprocessor","<nl>Newline 1<nl>Newline 2")
var tests_uppercase_result = pre(1,"Preprocessor","a <up>ThIs tExT sHoUlD bE uPpPeRcAsEd</up> b")
var tests_lowercase_result = pre(1,"Preprocessor","a <lo>ThIs tExT sHoUlD bE lOwErCaSeD</lo> b")
var tests_camelcase_result = pre(1,"Preprocessor","a <ca>thisShould_be_camel_CASEd</ca> b")
var tests_pascalcase_result = pre(1,"Preprocessor","a <pa>thisShould_be_pascal_CASEd</pa> b")
var tests_snakecase_result = pre(1,"Preprocessor","a <sn>thisShould_be_snake_CASEd</sn> b")
var tests_escapes_newlines_result = pre(1,"Prepreprocessor","<esc_nl>")
var tests_escapes_uppercase_result = pre(1,"Prepreprocessor","<esc_up></esc_up>")
var tests_escapes_lowercase_result = pre(1,"Prepreprocessor","<esc_lo></esc_lo>")
var tests_escapes_camelcase_result = pre(1,"Prepreprocessor","<esc_ca></esc_ca>")
var tests_escapes_pascalcase_result = pre(1,"Prepreprocessor","<esc_pa></esc_pa>")
var tests_escapes_snakecase_result = pre(1,"Prepreprocessor","<esc_sn></esc_sn>")
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 = "✔️ 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 <nl> 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("<nl>","\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("<nl>",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: <np> 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")