From e4094e1aa126b2f48ce4959d2e2b901c26d2e798 Mon Sep 17 00:00:00 2001 From: JeremyStarTM Date: Fri, 7 Jul 2023 04:10:53 +0200 Subject: [PATCH] Improve README, logger and preprocessor (a lot) --- README.md | 58 +++++++++++++----------- logger.gd | 8 ++-- preprocessor.gd | 116 +++++++++++++++++++++++++----------------------- 3 files changed, 98 insertions(+), 84 deletions(-) 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")