Update documentation (second commit)

This commit is contained in:
JeremyStar™ 2024-04-08 20:14:38 +02:00
parent 330bb98dd9
commit 5fed9c1f9b
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
27 changed files with 570 additions and 190 deletions

View file

@ -19,6 +19,7 @@
## ##
## This script is used to test CORE's behaviour during development. ## This script is used to test CORE's behaviour during development.
## It's state should be reverted to how it was before committing (if modified). ## It's state should be reverted to how it was before committing (if modified).
## For more permanent tests write a unit test instead.
extends Node extends Node
# CORE Configuration # CORE Configuration

View file

@ -1,22 +1,82 @@
--- ---
sidebar_position: 1 sidebar_position: 0
description: This is an easter egg.
--- ---
# About the CORE Framework # About the CORE Framework
The CORE Framework aims at simplifying development for developers writing their code in the [Godot Engine](https://godotengine.org), version *4.2*. The CORE Framework aims at simplifying development for developers writing their code in the [Godot Engine](https://godotengine.org), version *4.2*.
<!-- StarOpenSource Sky verification links -->
<link href="https://sky.staropensource.de/@staropensource"/> <link href="https://sky.staropensource.de/@staropensource"/>
<link href="https://sky.staropensource.de/@soscore"/> <link href="https://sky.staropensource.de/@soscore"/>
<!-- StarOpenSource Sky verification links -->
## Why does it exist? ## Why does it exist?
I ([JeremyStarTM](https://jstm.staropensource.de)) didn't want to write a new base every time I started another project. And that's why I made the CORE Framework, to serve as a common base for all my projects. I ([JeremyStarTM](https://git.staropensource.de/JeremyStarTM)) always wrote a new base for every project... which was not only wasting my time as I've rewritten the same stuff multiple times, often times not better than the last. And that's why I created the CORE Framework, to serve as the common base for my projects. My goal is to improve and push it as far as I can to make it a good and polished base for everyone.
## Should I use it? ## Should I use it?
If you want to use the CORE Framework in a new project, then your answer is **yes**! If you want to use the CORE Framework in an already existing project, be prepared to do some major refactoring. CORE implements it's own logging infrastructure, scene management, etc. and is not compatible with Godot's builtin/custom solutions. You can toggle them in the configuration file however. ### New projects
Your answer is *(probably)* **yes**!
### Existing projects
**No**, *unless* you want to do some major refactoring of your codebase. CORE implements it's own logging infrastructure, scene management and much more requiring you to essentially rewrite everything from scratch.
## Roadmap ## Comparison
- [x] Configuration support :::note
- [x] Logger implementation This table only compares frameworks that are relatively up to date with the Godot Engine (versions 4.1 and 4.2), can be found in the Godot Asset Library or are well known and are aimed at a specific game genre or general usage. Things like animation or dialogue frameworks are not in compared here.
- [x] HTTP Request helper :::
- [ ] Mod Loader <table>
- [x] Support for custom modules <tr>
- [ ] Extensible debugging console <th></th>
<th>CORE Framework</th>
<th><a href="https://github.com/Oplexitie/Cupcakes-Framework">Cupcakes Framework</a></th>
</tr>
<tr>
<td>Godot Versions</td>
<td>4.2</td>
<td>3.0 until 4.2</td>
</tr>
<tr>
<td>License</td>
<td>GNU AGPL v3</td>
<td>MIT</td>
</tr>
<tr>
<td>Commercial usage</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>Oriented at</td>
<td>General usage</td>
<td>FNAF-inspired games</td>
</tr>
<tr>
<td>Implements base features</td>
<td>For apps and games</td>
<td>FNAF-like game mechanics, no base for game though</td>
</tr>
<tr>
<td>Customizable</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Logger</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Scene Management</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Character AI</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>Made by</td>
<td><a href="https://staropensource.de">The StarOpenSource Project</a></td>
<td><a href="https://github.com/Oplexitie">Oplexitie</a></td>
</tr>
</table>

View file

@ -1,6 +1,6 @@
{ {
"label": "Getting started", "label": "Getting started",
"position": 3, "position": 2,
"link": { "link": {
"type": "generated-index", "type": "generated-index",
"description": "Helps you get CORE set up in your project." "description": "Helps you get CORE set up in your project."

View file

@ -1,5 +1,5 @@
--- ---
sidebar_position: 2 sidebar_position: 1
description: CORE needs to be initialized before usage. description: CORE needs to be initialized before usage.
--- ---
@ -10,22 +10,22 @@ This example should explain everything:
```gdscript ```gdscript
extends Node extends Node
# CORE Object
var core: Core var core: Core
# CORE Logger ## Gets a so called "logger instance". It basically saves you an argument on each log call.
## Gets a so called "logger instance". It basically saves you a argument on each log call.
@onready var logger: CoreLoggerInstance = core.logger.get_instance("path/to/script.gd") @onready var logger: CoreLoggerInstance = core.logger.get_instance("path/to/script.gd")
# Preinitialization phase
func _init() -> void: func _init() -> void:
# Create new CoreConfiguration # Create new CoreConfiguration
var config: CoreConfiguration = CoreConfiguration.new() var config: CoreConfiguration = CoreConfiguration.new()
# Set logger level to DIAG # Allow diagnostic and verbose messages
config.logger_level = CoreTypes.LoggerLevel.DIAG config.logger_level = CoreTypes.LoggerLevel.DIAG
# Initialize CORE with custom configuration # Initialize CORE with custom configuration
core = Core.new(config) core = Core.new(config)
# Initialize CORE with standard configuration # Initialize CORE with standard configuration, commented out
#core = Core.new() #core = Core.new()
# Initialization phase
func _ready() -> void: func _ready() -> void:
# Initialize CORE completely # Initialize CORE completely
await get_tree().process_frame # to avoid "setting up nodes" error await get_tree().process_frame # to avoid "setting up nodes" error

View file

@ -1,5 +1,5 @@
--- ---
sidebar_position: 1 sidebar_position: 0
--- ---
# Setting up # Setting up
@ -11,6 +11,20 @@ import TabItem from '@theme/TabItem';
This helps you install the CORE Framework in the first place. This helps you install the CORE Framework in the first place.
## Available branches
You can choose one of the following branches to install CORE with:
<Tabs groupId="explanation">
<TabItem value="develop" label="develop">
The **develop** branch features the latest commits to the framework but contains experimental and breaking changes.
It should never be used in production, not even in testing *unless* you know what you're doing or directly contributing to the framework.
</TabItem>
<TabItem value="stable" label="stable">
The **stable** branch features the latest update to the framework and does not break often. Alphas, betas and release candidates will not show up on the stable branch, only releases will.
This branch of the framework should always be used in production and testing as it doesn't break without a framework-breaking bug or you not being able to read the changelog correctly.
</TabItem>
</Tabs>
## Using the Godot Asset Library ## Using the Godot Asset Library
:::note :::note
This will install the CORE Framework without the ability to easily download updates. You will need to look for updates yourself and install the latest version from the Asset Library yourself. If you don't want that hassle, use a [git installation](#using-git) instead. This will install the CORE Framework without the ability to easily download updates. You will need to look for updates yourself and install the latest version from the Asset Library yourself. If you don't want that hassle, use a [git installation](#using-git) instead.
@ -92,7 +106,10 @@ git commit -m "Update CORE Framework"
</Tabs> </Tabs>
## Changing branches ## Changing branches
:::warning :::warning
Changing branches can result in errors and missing features. We don't accept issues regarding switching branches, you will be on your own! Changing branches is not supported by the CORE Framework maintainers and contributors.
Doing so anyway will result in missing features, potential refactoring work and you need to manually review every single commit since the last release (if coming from the stable branch). \
\
**Again, we don't recommend switching branches. Doing so anyway may lead to issues!**
::: :::
<Tabs groupId="git-branch"> <Tabs groupId="git-branch">
<TabItem value="direct-develop2stable" label="Develop » Stable"> <TabItem value="direct-develop2stable" label="Develop » Stable">

View file

@ -1,8 +1,8 @@
{ {
"label": "Reference", "label": "Reference",
"position": 4, "position": 3,
"link": { "link": {
"type": "generated-index", "type": "generated-index",
"description": "CORE Framework module documentation" "description": "CORE Framework reference"
} }
} }

View file

@ -6,6 +6,7 @@ description: Initializes and manages the framework.
# `CORE` # `CORE`
The **CORE Object** is responsible for initializing, managing and serving the CORE Framework. The **CORE Object** is responsible for initializing, managing and serving the CORE Framework.
## Versioning ## Versioning
### *int* <u>version_release</u> ### *int* <u>version_release</u>
CORE's version number. CORE's version number.
@ -27,42 +28,42 @@ Use these to access CORE's modules.
## Variables ## Variables
### *String* <u>basepath</u> ### *String* <u>basepath</u>
::danger[Don't modify] :::danger[Don't modify]
Do not modify this. Do not modify this.
:: :::
Stores the path to CORE's installation directory. Stores the path to CORE's installation directory.
### *Dictionary* <u>custom_modules</u> = *{}* ### *Dictionary* <u>custom_modules</u> = *{}*
### *void* <u>_ready</u>() ### *void* <u>_ready</u>()
::danger[Don't modify] :::danger[Don't modify]
Do not modify this. Do not modify this.
:: :::
Contains a list of all loaded custom modules. Contains a list of all loaded custom modules.
### *Node* <u>custom_modules_node</u> ### *Node* <u>custom_modules_node</u>
::danger[Don't modify] :::danger[Don't modify]
Do not modify this. Do not modify this.
:: :::
Contains the node holding all custom modules as children. Contains the node holding all custom modules as children.
## Functions ## Functions
### *void* <u>_init</u>(*CoreConfiguration* <u>new_config</u>) ### *void* <u>_init</u>(*CoreConfiguration* <u>new_config</u>)
::danger[Don't call] :::danger[Don't call]
Do not call this (except you're using `Core.new()`). Do not call this (except you're using `Core.new()`).
:: :::
Handles the preinitialization part. Does stuff like checking the engine version, loading the config and loading all modules into memory. Handles the preinitialization part. Does stuff like checking the engine version, loading the config and loading all modules into memory.
### *void* <u>_ready</u>() ### *void* <u>_ready</u>()
::danger[Don't call] :::danger[Don't call]
Do not call this. Do not call this.
:: :::
Handles the initialization part. Injects the builtin modules into the SceneTree and makes sure custom modules can be loaded properly. \ Handles the initialization part. Injects the builtin modules into the SceneTree and makes sure custom modules can be loaded properly. \
### *void* <u>initialize_modules</u>() ### *void* <u>initialize_modules</u>()
::danger[Don't call] :::danger[Don't call]
Do not call this. Do not call this.
:: :::
Initializes all built-in modules during the preinitialization phase. Initializes all built-in modules during the preinitialization phase.
### *void* <u>inject_modules</u>() ### *void* <u>inject_modules</u>()
::danger[Don't call] :::danger[Don't call]
Do not call this. Do not call this.
:: :::
Injects CORE's built-in modules into the SceneTree. Injects CORE's built-in modules into the SceneTree.
### *void* <u>complete_init</u>(*bool* <u>no_success_message</u> = *false*) ### *void* <u>complete_init</u>(*bool* <u>no_success_message</u> = *false*)
Waits for all built-in and custom modules to fully initialize. \ Waits for all built-in and custom modules to fully initialize. \
@ -79,9 +80,9 @@ Please note that you can't get CORE's built-in modules with this function.
### *void* <u>reload_configuration</u>(*CoreConfiguration* <u>new_config</u> = *CoreConfiguration.new()*) ### *void* <u>reload_configuration</u>(*CoreConfiguration* <u>new_config</u> = *CoreConfiguration.new()*)
Loads a (new) configuration object and applies it to all modules. Loads a (new) configuration object and applies it to all modules.
### *void* <u>apply_configuration</u>() ### *void* <u>apply_configuration</u>()
::danger[Don't call] :::danger[Don't call]
Do not call this. Do not call this.
:: :::
Applies the a configuration. Applies the a configuration.
### *void* <u>cleanup</u>() ### *void* <u>cleanup</u>()
Makes sure that CORE does not leak memory on shutdown/unload. \ Makes sure that CORE does not leak memory on shutdown/unload. \
@ -110,7 +111,7 @@ You can use the following placeholders:
### *Array[int]* <u>get_version_semantic</u>() ### *Array[int]* <u>get_version_semantic</u>()
Returns the CORE version in the semantic versioning scheme. The first integer contains the version number, the second integer contains the version type (`0` for alpha, `1` for beta, `2` for rc and `3` for release) and the last integer contains the version type number. Returns the CORE version in the semantic versioning scheme. The first integer contains the version number, the second integer contains the version type (`0` for alpha, `1` for beta, `2` for rc and `3` for release) and the last integer contains the version type number.
### *bool* <u>determine_basepath</u>() ### *bool* <u>determine_basepath</u>()
::danger[Don't call] :::danger[Don't call]
Do not call this. Do not call this.
:: :::
Determines CORE's installation/base path. Determines CORE's installation/base path.

View file

@ -7,6 +7,7 @@ description: Template for CORE modules
Provides a basic template and a common foundation for building CORE modules. \ Provides a basic template and a common foundation for building CORE modules. \
It provides common functions and variables used in all CORE modules. It provides common functions and variables used in all CORE modules.
## Variables ## Variables
### *Core* <u>core</u> ### *Core* <u>core</u>
Contains a reference to the [CORE Object](/reference/core). Contains a reference to the [CORE Object](/reference/core).

View file

@ -1,5 +1,6 @@
--- ---
sidebar_position: 1 sidebar_position: 1
description: The framework configuration
--- ---
# `CoreConfiguration` # `CoreConfiguration`
@ -7,6 +8,7 @@ Provides the default configuration for the CORE Framework.
## Note ## Note
All settings are variables. All settings are variables.
## Global ## Global
### *bool* <u>headless</u> = *false* ### *bool* <u>headless</u> = *false*
Controls CORE's functionality. Renders GUI-related modules useless when set to `false`, which is the recommended behaviour on servers. For CORE's full functionality, set this to `true`. Controls CORE's functionality. Renders GUI-related modules useless when set to `false`, which is the recommended behaviour on servers. For CORE's full functionality, set this to `true`.
@ -20,32 +22,24 @@ Allows or disallows custom modules.
## Logger ## Logger
### *CoreTypes.LoggerLevel* <u>logger_level</u> = *CoreTypes.LoggerLevel.INFO* ### *CoreTypes.LoggerLevel* <u>logger_level</u> = *CoreTypes.LoggerLevel.INFO*
I don't have to explain this, do I? The minimum log level you want to be displayed.
### *bool* <u>logger_colored</u> = *true* ### *bool* <u>logger_colored</u> = *true*
Toggles colored output. Set to `false` if you don't want that. Determines if the logger's output should be colored.
### *String* <u>logger_format</u> = *"%color%[%time%] [%level% %source%:%line%] %message%"* ### *String* <u>logger_format</u> = *"%color%[%time%] [%level% %source%:%line%] %message%"*
The format string the logger will operate on. The template for all log messages
Available placeholders are: `%time%`, `%time_ms%`, `%level%`, `%color%`, `%message%`, `%source%`, `%source_raw%`, `%function%` and `%line%` Available placeholders are: `%time%`, `%time_ms%`, `%level%`, `%color%`, `%message%`, `%source%`, `%source_raw%`, `%function%` and `%line%`
### *bool* <u>logger_newlines_override</u> = *true* ### *bool* <u>logger_newlines_override</u> = *true*
This example should make it clear, what this does: Determines if identation should be provided if the logger encounters a newline.
```plain
logger_newlines_override = true:
[09:47:00] [INFO Test.gd:69] This is a test message...
with a newline!
logger_newlines_override = false:
[09:47:00] [INFO Test.gd:69] This is a test message...
with a newline!
```
### *int* <u>logger_newlines_sizelimit</u> = *40* ### *int* <u>logger_newlines_sizelimit</u> = *40*
The maximum amount of characters than can appear before `%message%` before newlines won't be overriden. Setting this variable to `-1` disables this behaviour. The maximum amount of characters excluding the message before newlines are no longer idented. Set to `-1` to disable this behaviour.
## LogUI ## Log UI
### *bool* <u>logui_enabled</u> = *true* ### *bool* <u>logui_enabled</u> = *true*
Determines if [`LogUI`](/terminology#logui) should be visible or not. Enables or disables [Log UI](/terminology#logui).
### *Color* <u>logui_background_color</u> = *Color.BLACK* ### *Color* <u>logui_background_color</u> = *Color.BLACK*
The color the `LogUI` background will have. Set to `Color.TRANSPARENT` for a transparent background. The Log UI background color.. Set to `Color.TRANSPARENT` for a transparent background.
### *int* <u>logui_font_size</u> = *14* ### *int* <u>logui_font_size</u> = *14*
What size the graphical log should have. What font size the graphical log should have.
## Easy Request Maker ## Easy Request Maker
### *CoreTypes.BlockadeLevel* <u>erm_unsecure_requests</u> = *CoreTypes.BlockadeLevel.BLOCK* ### *CoreTypes.BlockadeLevel* <u>erm_unsecure_requests</u> = *CoreTypes.BlockadeLevel.BLOCK*

View file

@ -6,6 +6,7 @@ description: Contains various enums.
# `CoreTypes` # `CoreTypes`
Contains globaly accessible custom enums and types used throughout the CORE Framework's source code. Contains globaly accessible custom enums and types used throughout the CORE Framework's source code.
## Enums ## Enums
### <u>VersionType</u>{ RELEASE, RELEASECANDIDATE, BETA, ALPHA } ### <u>VersionType</u>{ RELEASE, RELEASECANDIDATE, BETA, ALPHA }
Available version types, following the StarOpenSource Versioning Specification (SOSVS) version 1. Available version types, following the StarOpenSource Versioning Specification (SOSVS) version 1.

View file

@ -1,9 +1,30 @@
--- ---
sidebar_position: 8 sidebar_position: 8
description: Allows for awaited, batched and oneline requests.
--- ---
# `Easy Request Maker` # `Easy Request Maker`
Allows for awaited, batched and oneline requests. Makes it easy to download files off the internet and communicate with HTTP servers.
## Variables
### *Dictionary* <u>list_queue</u> = *{}*
:::danger[Don't modify]
Do not modify this.
:::
Contains a list of all queued downloads.
### *Dictionary* <u>list_active</u> = *{}*
:::danger[Don't modify]
Do not modify this.
:::
Contains a list of all active downloads.
### *Dictionary* <u>list_complete</u> = *{}*
:::danger[Don't modify]
Do not modify this.
:::
Contains a list of all completed downloads.
## Functions ## Functions
### *Dictionary* <u>awaited_request</u>(*String* <u>url</u>, *bool* <u>parse_utf8</u>, *HTTPClient.Method* <u>method</u> = *HTTPClient.Method.METHOD_GET*, *PackedStringArray* <u>headers</u> = *PackedStringArray([])*, *String* <u>data</u> = *""*) ### *Dictionary* <u>awaited_request</u>(*String* <u>url</u>, *bool* <u>parse_utf8</u>, *HTTPClient.Method* <u>method</u> = *HTTPClient.Method.METHOD_GET*, *PackedStringArray* <u>headers</u> = *PackedStringArray([])*, *String* <u>data</u> = *""*)
@ -27,7 +48,7 @@ The returned `Dictionary` has the following structure (example):
:::note[Awaiting required] :::note[Awaiting required]
Using the `await` keyword is required for this function. Using the `await` keyword is required for this function.
::: :::
Returns a file from the internet without returning the godot code, http code or headers. Useful for oneliners. Requests a file from the internet without returning the godot code, http code or headers. Useful for oneliners.
Returns `null` on error. To ignore HTTP errors (ie. non-200 statuses) set `ignore_http_code` to `true`. Returns `null` on error. To ignore HTTP errors (ie. non-200 statuses) set `ignore_http_code` to `true`.
Returns a UTF-8 string with `return_utf8` turned on, returns bytes when turned off. Returns a UTF-8 string with `return_utf8` turned on, returns bytes when turned off.
@ -49,3 +70,29 @@ The returned `Dictionary`s have the following structure (example):
| ---------------------------------------------------------------------- The HTTP response code | ---------------------------------------------------------------------- The HTTP response code
------------------------------------------------------------------------------------ Equal to @GlobalScope.Error. If not 0/Error.OK = the request failed ------------------------------------------------------------------------------------ Equal to @GlobalScope.Error. If not 0/Error.OK = the request failed
``` ```
### *int* <u>generate_id</u>()
:::danger[Don't call]
Do not call this.
:::
Returns a new download id.
### *int* <u>create_request</u>(*String* <url>, *HTTPClient.Method* <u>method</u> = *HTTPClient.Method.METHOD_GET*, *PackedStringArray* <u>headers</u> = *PackedStringArray([])*, *String* <u>body</u> = *""*)
:::warning
You'll probably not need this. Only use this function when implementing your own downloading method.
:::
Creates a new request and stores it in the queue. Returns the download id.
### *void* <u>start_request</u>(*int* <u>id</u>, *bool* <u>parse_utf8</u>)
:::note[Awaiting required]
Using the `await` keyword is required for this function.
:::
:::warning
You'll probably not need this. Only use this function when implementing your own downloading method.
:::
Configures and starts a queued request.
### *bool* <u>is_url_allowed</u>(*String* <url>)
Checks if `url` can be used.
### *bool* <u>is_request_completed</u>(*int* <u>id</u>)
Returns if a request has completed yet.
### *void* <u>clean_queue</u>()
Cleans the request queue.
### *void* <u>clean_completed</u>()
Cleans the completed requests list.

View file

@ -1,9 +1,11 @@
--- ---
sidebar_position: 4 sidebar_position: 4
description: Your usual basic logger implementation, with some extra features.
--- ---
# `Logger` # `Logger`
Prints formatted strings into the console/log. Allows for colored output, better newlines, multiple logger levels and a large variety of placeholders usable in 'config_format'.
## Signals ## Signals
### <u>log_event</u> ### <u>log_event</u>
@ -14,25 +16,30 @@ Emitted on any log call, permitted or not. \
**format** is set to `""` when **allowed** is set `false`. **format** is set to `""` when **allowed** is set `false`.
## Functions ## Functions
### *CoreLoggerInstance* <u>get_instance</u>(*String* <u>origin</u>) ### *void* <u>_log</u>(*CoreTypes.LoggerLevel* <u>level</u>, *String* <u>origin</u>, *String* <u>message</u>)
Returns a [logger instance](/reference/loggerinstance), which are two fancy words meaning you don't need to pass <u>origin</u> every time you want to log something. :::danger[Don't call]
### *bool* <u>is_level_allowed</u>(*CoreTypes.LoggerLevel* <u>level</u>) Do not call this.
Checks if the specified log level is permitted by the current configuration. :::
The main logging function that does the heavy lifting.
### *void* <u>diag</u>(*String* <u>origin</u>, *String* <u>message</u>) ### *void* <u>diag</u>(*String* <u>origin</u>, *String* <u>message</u>)
Prints a diagnostic message Prints a diagnostic message.
### *void* <u>verb</u>(*String* <u>origin</u>, *String* <u>message</u>) ### *void* <u>verb</u>(*String* <u>origin</u>, *String* <u>message</u>)
Prints a verbose message Prints a verbose message.
### *void* <u>info</u>(*String* <u>origin</u>, *String* <u>message</u>) ### *void* <u>info</u>(*String* <u>origin</u>, *String* <u>message</u>)
Prints an informational message Prints an informational message.
### *void* <u>warn</u>(*String* <u>origin</u>, *String* <u>message</u>) ### *void* <u>warn</u>(*String* <u>origin</u>, *String* <u>message</u>)
Prints a warning message Prints a warning message.
### *void* <u>error</u>(*String* <u>origin</u>, *String* <u>message</u>) ### *void* <u>error</u>(*String* <u>origin</u>, *String* <u>message</u>)
Prints an error message Prints an error message.
### *void* <u>crash</u>(*String* <u>origin</u>, *String* <u>message</u>, *bool* <u>framework_crash</u> = *false*) ### *void* <u>crash</u>(*String* <u>origin</u>, *String* <u>message</u>, *bool* <u>framework_crash</u> = *false*)
:::note[Awaiting required] :::note[Awaiting required]
Using the `await` keyword is required for this function. Using the `await` keyword is required for this function.
::: :::
:::danger :::danger
Please do not set `framework_crash` to `true`. Thank you. Don't set `framework_crash` to `true`, thanks!
::: :::
Handles crashes. Will terminate your game/application immediately. Handles crashes. Will terminate your game/application immediately.
### *bool* <u>is_level_allowed</u>(*CoreTypes.LoggerLevel* <u>level</u>)
Checks if the specified log level is allowed by the current configuration.
### *CoreLoggerInstance* <u>get_instance</u>(*String* <u>origin</u>)
Returns a [CoreLoggerInstance](/reference/loggerinstance), which is a fancy word meaning you don't need to pass `origin` every time you want to log something.

View file

@ -4,10 +4,8 @@ description: Passes `origin` for you.
--- ---
# `LoggerInstance` # `LoggerInstance`
Pretty much a wrapper around CORE's logging implementation. \ Pretty much a wrapper around CORE's logging implementation. CoreLoggerInstance's only job is to save you some effort aka. you not needing to pass the `origin` argument to each and every log call, which is extremely annoying. Thank us later ;)
CoreLoggerInstance's only job is to save you some effort aka. \
you not needing to pass the `origin` argument to each \
and every log call, which is extremely annoying. Thank us later ;)
## Variables ## Variables
### *CoreBaseModule* <u>logger</u> ### *CoreBaseModule* <u>logger</u>

View file

@ -1,18 +1,21 @@
--- ---
sidebar_position: 6 sidebar_position: 6
description: Contains various utility functions.
--- ---
# `Miscellaneous` # `Miscellaneous`
Miscellaneous functions that don't fit into other modules. This module contains many methods that don't fit into any other module and generally make your life as a developer easier.
## Functions ## Functions
### *void* <u>quit_safely</u>(*int* <u>exitcode</u> = *0*) ### *void* <u>quit_safely</u>(*int* <u>exitcode</u> = *0*)
:::note[Awaiting required] :::note[Awaiting required]
Using the `await` keyword is required for this function. Using the `await` keyword is required for this function.
::: :::
Adds an small extra delay before exiting. Highly recommended over calling `get_tree().quit()` yourself. Makes sure for all log messages to be flushed and that CORE is correctly cleaned up.
Using `get_tree().quit()` directly may cause various issues.
### *float* <u>byte2mib</u>(*int* <u>bytes</u>, *bool* flatten = *true*) ### *float* <u>byte2mib</u>(*int* <u>bytes</u>, *bool* flatten = *true*)
Converts a number of bytes to mebibytes. Converts a number of bytes into mebibytes.
If `flatten` is set to `true`, the decimal part will be discarded. If `flatten` is set to `true`, the decimal part will be discarded.
### *float* <u>mib2byte</u>(*float* <u>mib</u>, *bool* <u>flatten</u> = *true*) ### *float* <u>mib2byte</u>(*float* <u>mib</u>, *bool* <u>flatten</u> = *true*)
@ -30,7 +33,7 @@ If `flatten` is set to `true`, the decimal part will be discarded.
### *String* <u>format_stringarray</u>(*Array[String]* <u>array</u>, *String* <u>item_before</u> = *""*, *String* <u>item_after</u> = *""*, *String* <u>separator_list</u> = *", "*, *String* <u>separator_final</u> = *" & "*) ### *String* <u>format_stringarray</u>(*Array[String]* <u>array</u>, *String* <u>item_before</u> = *""*, *String* <u>item_after</u> = *""*, *String* <u>separator_list</u> = *", "*, *String* <u>separator_final</u> = *" & "*)
Converts a string array into a normal, nicely formatted string. Converts a string array into a normal, nicely formatted string.
With `item_before` and `item_after` you can customize the lists appearance. Here's a example on how to format every item bold: With `item_before` and `item_after` you can customize the lists appearance. Here's an example on how to format every item bold:
```gdscript ```gdscript
extends Node extends Node

View file

@ -1,34 +1,66 @@
--- ---
sidebar_position: 7 sidebar_position: 7
description: Manages scenes for you efficiently.
--- ---
# `Scene Management System` # `Scene Management System`
Handles scenes and their order. Allows for organized scene management, making development much faster.
## Constants
## *Array[String]* <u>scene_nodes</u> = *[ "debug", "cutscene", "menu", "main", "background" ]*
Used internally for adding, managing and removing scene collections.
## Variables
## *Node* <u>scenes_debug</u> = *Node.new()*
:::danger[Don't modify]
Do not modify this.
:::
The 'debug' scene collection.
## *Node* <u>scenes_cutscene</u> = *Node.new()*
:::danger[Don't modify]
Do not modify this.
:::
The 'cutscene' scene collection.
## *Node* <u>scenes_menu</u> = *Node.new()*
:::danger[Don't modify]
Do not modify this.
:::
The 'menu' scene collection.
## *Node* <u>scenes_main</u> = *Node.new()*
:::danger[Don't modify]
Do not modify this.
:::
The 'main' scene collection.
## *Node* <u>scenes_background</u> = *Node.new()*
:::danger[Don't modify]
Do not modify this.
:::
The 'background' scene collection.
## *Dictionary* <u>scenes</u> = *{}*
:::danger[Don't modify]
Do not modify this.
:::
A list of all loaded scenes
## Functions ## Functions
### *bool* <u>add_scene</u>(*String* <u>sname</u>, *Node* <u>sclass</u>, *CoreTypes.SceneType* <u>type</u>) ### *bool* <u>add_scene</u>(*String* <u>sname</u>, *Node* <u>sclass</u>, *CoreTypes.SceneType* <u>type</u>)
Adds a scene to some scene collection. Adds a scene to some scene collection.
Returns `true` if successful.
### *bool* <u>remove_scene</u>(*String* <u>sname</u>, *bool* <u>force_remove</u> = *false*) ### *bool* <u>remove_scene</u>(*String* <u>sname</u>, *bool* <u>force_remove</u> = *false*)
:::danger :::danger
Please do not set `force_remove` to `true`. Thank you. Don't set `force_remove` to `true`, thanks!
::: :::
Removes a scene from some scene collection. Removes a scene from some scene collection.
Returns `true` if successful.
### *Node* <u>get_scene</u>(*String* <u>sname</u>) ### *Node* <u>get_scene</u>(*String* <u>sname</u>)
Returns a scene from some scene collection. Returns a scene from some scene collection. \
\
Returns `null` if no scene with that name was found. Returns `null` if no scene with that name was found.
### *Node* <u>get_scene_collection</u>(*CoreTypes.SceneType* <u>type</u>) ### *Node* <u>get_scene_collection</u>(*CoreTypes.SceneType* <u>type</u>)
:::danger :::danger
NEVER change a scene collection's properties or free it! You can CRASH the CORE Framework easily by doing this! Don't change any properties of the scene collection or free it, otherwise you may cause breakage.
::: :::
:::danger Returns a scene collection node. \
NEVER free a scene yourself! You can CRASH the CORE Framework easily by doing this! Useful if you want to change a child's index.
:::
Returns a scene collection node. Useful if you want to change the node's position or want direct access to one.
### *Array[Node]* <u>get_scene_collection_list</u>(*CoreTypes.SceneType* <u>type</u>) ### *Array[Node]* <u>get_scene_collection_list</u>(*CoreTypes.SceneType* <u>type</u>)
Returns a list of all loaded scenes in some scene collection. Returns a list of all loaded scenes in some scene collection.
### *int* <u>get_scene_collection_count</u>(*CoreTypes.SceneType* <u>type</u>) ### *int* <u>get_scene_collection_count</u>(*CoreTypes.SceneType* <u>type</u>)
@ -36,4 +68,4 @@ Returns the number of loaded scenes in some scene collection.
### *CoresTypes.SceneType* <u>exists</u>(*String* <u>sname</u>) ### *CoresTypes.SceneType* <u>exists</u>(*String* <u>sname</u>)
Returns the scene collection a scene is loaded in. Returns the scene collection a scene is loaded in.
Returns `CoreTypes.SceneType.NONE` if no scene with that name has been found. Returns `CoreTypes.SceneType.NONE` if no scene with that name was found.

View file

@ -1,20 +1,32 @@
--- ---
sidebar_position: 9 sidebar_position: 9
description: Easy config management.
--- ---
# `Storage` # `Storage`
Allows you to write configuration files with ease, without any headaches. Allows you to write configuration files with ease, without any headaches.
## Variables ## Variables
### *bool* <u>is_open</u> ### *bool* <u>is_open</u> = *false*
:::danger[Do not modify] :::danger[Don't modify]
NEVER change the value of this variable. You will break stuff with this! Do not modify this.
::: :::
Indicates if a storage file is currently open. Indicates if a storage file is currently open.
### *Dictionary* <u>storage</u> = *{}*
:::danger[Don't modify]
Do not modify this.
:::
The parsed data inside the storage file.
### *String* <u>storage_location</u> = *""*
:::danger[Don't modify]
Do not modify this.
:::
The location of the storage file.
## Functions ## Functions
### *bool* <u>open_storage</u>(*String* <u>location</u>, *bool* <u>create_new</u> = *true*, *bool* <u>sanity_check</U> = *true*, *bool* <u>fail_on_sanity_check</u> = *false*) ### *bool* <u>open_storage</u>(*String* <u>location</u>, *bool* <u>create_new</u> = *true*, *bool* <u>sanity_check</U> = *true*, *bool* <u>fail_on_sanity_check</u> = *false*)
Loads a storage file from `location` and creates a new one first if missing (`create_new`). Also performs basic sanity checking (`sanity_check`) and may throw an error on failure (`fail_on_sanity_check`). Loads a storage file into memory.
### *bool* <u>close_storage</u>() ### *bool* <u>close_storage</u>()
Closes the active storage file. Closes the active storage file.
### *bool* <u>save_storage</u>() ### *bool* <u>save_storage</u>()
@ -28,8 +40,10 @@ Updates a storage key with the specified value.
### *bool* <u>del_key</u>(*String* <u>key</u>, *bool* <u>autosave</u> = *true*) ### *bool* <u>del_key</u>(*String* <u>key</u>, *bool* <u>autosave</u> = *true*)
Deletes a storage key. Deletes a storage key.
### *Dictionary* <u>get_dict</u>() ### *Dictionary* <u>get_dict</u>()
Returns the `storage` dictionary, useful for more advanced operations. Changes are not reflected onto the `storage` dictionary though. To save changes through this module, pass your modified dictionary to [`save_dict`](#bool-save_dictdictionary-dict-bool-sanity_check--true-bool-fail_on_sanity_check--false-bool-autosave--true). Returns the `storage` `Dictionary`, useful for more advanced operations. \
Changes are not reflected onto the `storage` dictionary though. To save changes through this module, \
pass your modified dictionary to `save_dict`.
### *bool* <u>save_dict</u>(*Dictionary* <u>dict</u>, *bool* <u>sanity_check</u> = *true*, *bool* <u>fail_on_sanity_check</u> = *false*, *bool* <u>autosave</u> = *true*) ### *bool* <u>save_dict</u>(*Dictionary* <u>dict</u>, *bool* <u>sanity_check</u> = *true*, *bool* <u>fail_on_sanity_check</u> = *false*, *bool* <u>autosave</u> = *true*)
Saves a arbitrary dictionary as a `storage` dictionary with sanity checking (`sanity_check` and `fail_on_sanity_check`). Saves a arbitrary dictionary as a `storage` dictionary with sanity checking (`sanity_check` and `fail_on_sanity_check`).
### *Array[String]* <u>perform_sanity_check</u>(*Dictionary* <u>storage_check</u>) ### *Array[String]* <u>perform_sanity_check</u>(*Dictionary* <u>storage_check</u>)
Performs sanity checks on a dictionary aka. checks the type of all keys and their values. Performs sanity checks on a [class Dictionary] to determine if it can be saved and loaded using this module.

View file

@ -1,17 +1,25 @@
--- ---
sidebar_position: 2 sidebar_position: 1
description: You don't know a word? Look it up here.
--- ---
# Terminology # Terminology
You don't know a word? Look it up here.
## CORE Object aka. `CORE` ## CORE Object aka. `CORE`
The **CORE Object** is the class you use to initialize the CORE Framework. The **CORE Object** is the class you use to initialize the framework. It holds all modules and initializes and manages the framework.
## `Log UI`
Displays the log/console output graphically in the background. ## Log UI
## `ERM` Displays the log/console output shown graphically in the background.
## ERM
Stands for **Easy Request Maker** and allows you to download stuff. Stands for **Easy Request Maker** and allows you to download stuff.
## `EDL`
The old name for the [`ERM`](#erm) module, which was called `Easy DownLoader` previously. ## EDL
## `SMS` The old name for the [`ERM`](#erm) module. Stood for `Easy DownLoader`.
## SMS
No, it does not stand for **Short Message Service**, but for **Scene Management System**. It manages your scenes. No, it does not stand for **Short Message Service**, but for **Scene Management System**. It manages your scenes.
## CMS
Stands for **Custom Module Support**.

View file

@ -15,8 +15,8 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
## Template for CORE modules.[br] ## Template for CORE modules.
## [br] ##
## Provides a basic template and a common foundation for building CORE modules.[br] ## Provides a basic template and a common foundation for building CORE modules.[br]
## It provides common functions and variables used in all CORE modules. ## It provides common functions and variables used in all CORE modules.
extends Node extends Node

View file

@ -2,8 +2,9 @@
# Copyright (c) 2024 The StarOpenSource Project & Contributors # Copyright (c) 2024 The StarOpenSource Project & Contributors
# Licensed in the Public Domain # Licensed in the Public Domain
## The [code]CoreConfiguration[/code] class holds the Framework's settings.[br] ## The framework configuration
## The default configuration is designed to be usable without any modification. ##
## Provides the default configuration for the CORE Framework.
extends Node extends Node
class_name CoreConfiguration class_name CoreConfiguration
@ -18,30 +19,23 @@ class_name CoreConfiguration
## Allows or disallows custom modules. ## Allows or disallows custom modules.
@export var custom_modules: bool @export var custom_modules: bool
@export_category("Logger") @export_category("Logger")
## I don't have to explain this, do I? ## The minimum log level you want to be displayed.
@export var logger_level: CoreTypes.LoggerLevel @export var logger_level: CoreTypes.LoggerLevel
## Toggles colored output. Set to [code]false[/code] if you don't want that. ## Determines if the logger's output should be colored.
@export var logger_colored: bool @export var logger_colored: bool
## The format string the logger will operate on. Available placeholders are: [code]%time%[/code], [code]%time_ms%[/code], [code]%level%[/code], [code]%color%[/code], [code]%message%[/code], [code]%source%[/code], [code]%source_raw%[/code], [code]%function%[/code] and [code]%line%[/code] ## The template for all log messages.[br]
## Available placeholders are: [code]%time%[/code], [code]%time_ms%[/code], [code]%level%[/code], [code]%color%[/code], [code]%message%[/code], [code]%source%[/code], [code]%source_raw%[/code], [code]%function%[/code] and [code]%line%[/code]
@export var logger_format: String @export var logger_format: String
## This example should make it clear, what this does:[br] ## Determines if identation should be provided if the logger encounters a newline.
## [codeblock]
## logger_newlines_override = true:
## [09:47:00] [INFO Test.gd:69] This is a test message...
## with a newline!
## logger_newlines_override = false:
## [09:47:00] [INFO Test.gd:69] This is a test message...
## with a newline!
## [/codeblock]
@export var logger_newlines_override: bool @export var logger_newlines_override: bool
## The maximum amount of characters than can appear before [code]%message%[/code] before newlines won't be overriden. Setting this variable to [code]-1[/code] disables this behaviour. ## The maximum amount of characters excluding the message before newlines are no longer idented. Set to [code]-1[/code] to disable this behaviour.
@export var logger_newlines_sizelimit: int @export var logger_newlines_sizelimit: int
@export_category("LogUI") @export_category("Log UI")
## Determines if [code]LogUI[/code] should be visible or not. ## Enables or disables Log UI.
@export var logui_enabled: bool @export var logui_enabled: bool
## The color the [code]LogUI[/code] background will have. Set to [code]Color.TRANSPARENT[/code] for a transparent background. ## The Log UI background color. Set to [code]Color.TRANSPARENT[/code] for a transparent background.
@export var logui_background_color: Color @export var logui_background_color: Color
## What size the graphical log should have. ## What font size the graphical log should have.
@export var logui_font_size: int @export var logui_font_size: int
@export_category("Easy Request Maker") @export_category("Easy Request Maker")
## Determines how unsecure requests should be handled. ## Determines how unsecure requests should be handled.
@ -60,7 +54,7 @@ func _init() -> void:
logger_format = "%color%[%time%] [%level% %origin%] %message%" logger_format = "%color%[%time%] [%level% %origin%] %message%"
logger_newlines_override = true logger_newlines_override = true
logger_newlines_sizelimit = 40 logger_newlines_sizelimit = 40
# LogUI # Log UI
logui_enabled = true logui_enabled = true
logui_background_color = Color.BLACK # To disable the background, use Color.TRANSPARENT logui_background_color = Color.BLACK # To disable the background, use Color.TRANSPARENT
logui_font_size = 14 logui_font_size = 14

View file

@ -15,11 +15,11 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
## Passes [code]origin[/code] for you.[br] ## Passes [code]origin[/code] for you.
## [br] ##
## Pretty much a wrapper around CORE's logging implementation.[br] ## Pretty much a wrapper around CORE's logging implementation.
## CoreLoggerInstance's only job is to save you some effort aka.[br] ## CoreLoggerInstance's only job is to save you some effort aka.
## you not needing to pass the [code]origin[/code] argument to each[br] ## you not needing to pass the [code]origin[/code] argument to each
## and every log call, which is extremely annoying. Thank us later ;) ## and every log call, which is extremely annoying. Thank us later ;)
extends Node extends Node
class_name CoreLoggerInstance class_name CoreLoggerInstance
@ -38,12 +38,12 @@ func _init(logger_new: CoreBaseModule, origin_new: String) -> void:
func diag(message: String) -> void: logger.diag(origin, message) func diag(message: String) -> void: logger.diag(origin, message)
## Prints a verbose message. ## Prints a verbose message.
func verb(message: String) -> void: logger.verb(origin, message) func verb(message: String) -> void: logger.verb(origin, message)
## Prints a informational message. ## Prints an informational message.
func info(message: String) -> void: logger.info(origin, message) func info(message: String) -> void: logger.info(origin, message)
## Prints a warning message. ## Prints a warning message.
func warn(message: String) -> void: logger.warn(origin, message) func warn(message: String) -> void: logger.warn(origin, message)
## Prints a error message. ## Prints an error message.
func error(message: String) -> void: logger.error(origin, message) func error(message: String) -> void: logger.error(origin, message)
## Handles crashes. Will terminate your game/application immediately. ## Handles crashes. Will terminate your game/application immediately.
## Note: Awaiting required. ## Note: Using the [code]await[/code] keyword is required for this function.
func crash(message: String) -> void: await logger.crash(origin, message) func crash(message: String) -> void: await logger.crash(origin, message)

View file

@ -15,7 +15,9 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
## Contains enums and types shared across the CORE Framework. ## Contains various enums.
##
## Contains globaly accessible custom enums and types used throughout the CORE Framework's source code.
extends Node extends Node
class_name CoreTypes class_name CoreTypes

View file

@ -18,11 +18,20 @@
## Allows for awaited, batched and oneline requests. ## Allows for awaited, batched and oneline requests.
extends CoreBaseModule extends CoreBaseModule
## Contains a list of all queued downloads.[br]
## Danger: Do not modify this.
var list_queue: Dictionary = {} var list_queue: Dictionary = {}
## Contains a list of all active downloads.[br]
## Danger: Do not modify this.
var list_active: Dictionary = {} var list_active: Dictionary = {}
## Contains a liust of all completed downloads.[br]
## Danger: Do not modify this.
var list_complete: Dictionary = {} var list_complete: Dictionary = {}
## Determines how unsecure requests should be handled.
var config_unsecure_requests: CoreTypes.BlockadeLevel var config_unsecure_requests: CoreTypes.BlockadeLevel
# +++ module +++
func _cleanup() -> void: func _cleanup() -> void:
clean_queue() clean_queue()
clean_completed() clean_completed()
@ -32,12 +41,21 @@ func _cleanup() -> void:
await get_tree().process_frame await get_tree().process_frame
remove_child(child) remove_child(child)
func generate_id() -> int: # +++ methods that do the heavily lifting +++
var id = randi() ## Requests a file from the internet.[br]
if list_queue.has(id) or list_active.has(id): return generate_id() ## [br]
logger.diagf("erm", "Generated new download id " + str(id)) ## The returned [code]Dictionary[/code] has the following structure (example):[br]
return id ## [codeblock]
## { "result": 0, "http_code": 200, "headers": [ "Server": "nginx" ], "body": [], "body_utf8": [] }
## ^ ^ ^ ^ ^
## | | | | |
## | | | | --------- The body from the server, as a UTF-8 string (set to "" if 'parse_utf8' is false)
## | | | ----------------------- The body from the server, as bytes
## | | ------------------------------------------------------ A array of headers
## | ---------------------------------------------------------------------- The HTTP response code
## ------------------------------------------------------------------------------------ Equal to @GlobalScope.Error. If not 0/Error.OK = the request failed
## [/codeblock][br]
## Note: Using the [code]await[/code] keyword is required for this function.
func awaited_request(url: String, parse_utf8: bool, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), data: String = "") -> Dictionary: func awaited_request(url: String, parse_utf8: bool, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), data: String = "") -> Dictionary:
logger.verbf("erm", "Creating awaited request") logger.verbf("erm", "Creating awaited request")
if !await is_url_allowed(url): return {} if !await is_url_allowed(url): return {}
@ -49,6 +67,11 @@ func awaited_request(url: String, parse_utf8: bool, method: HTTPClient.Method =
list_complete.erase(id) list_complete.erase(id)
return dldata return dldata
## Requests a file from the internet without returning the godot code, http code or headers. Useful for oneliners.[br]
## [br]
## Returns [code]null[/code] on error. To ignore HTTP errors (ie. non-200 statuses) set [code]ignore_http_code[/code] to [code]true[/code].[br]
## Returns a UTF-8 string with [code]return_utf8[/code] turned on, returns bytes when turned off.[br]
## Note: Using the [code]await[/code] keyword is required for this function.
func oneline_awaited_request(url: String, return_utf8: bool = true, ignore_http_code: bool = false, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), data: String = "") -> Variant: func oneline_awaited_request(url: String, return_utf8: bool = true, ignore_http_code: bool = false, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), data: String = "") -> Variant:
var dldata: Dictionary = await awaited_request(url, return_utf8, method, headers, data) var dldata: Dictionary = await awaited_request(url, return_utf8, method, headers, data)
if dldata == {}: return null if dldata == {}: return null
@ -58,6 +81,21 @@ func oneline_awaited_request(url: String, return_utf8: bool = true, ignore_http_
if return_utf8: return dldata["body_utf8"] if return_utf8: return dldata["body_utf8"]
else: return dldata["body"] else: return dldata["body"]
## Requests multiple files from the internet.[br]
## [br]
## Thee returned [code]Dictionary[/code]s have the following structure (example):
## [codeblock]
## { "result": 0, "http_code": 200, "headers": [ "Server": "nginx" ], "body": [], "body_utf8": [] }
## ^ ^ ^ ^ ^
## | | | | |
## | | | | --------- The body from the server, as a UTF-8 string (set to "" if 'parse_utf8' is false)
## | | | ----------------------- The body from the server, as bytes
## | | ------------------------------------------------------ A array of headers
## | ---------------------------------------------------------------------- The HTTP response code
## ------------------------------------------------------------------------------------ Equal to @GlobalScope.Error. If not 0/Error.OK = the request failed
## [/codeblock][br]
## Note: Using the [code]await[/code] keyword is required for this function.
func batch_awaited_request(urls: PackedStringArray, parse_utf8: bool, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), data: String = "") -> Array[Dictionary]: func batch_awaited_request(urls: PackedStringArray, parse_utf8: bool, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), data: String = "") -> Array[Dictionary]:
logger.verbf("erm", "Creating " + str(urls.size()) + " awaited request(s)") logger.verbf("erm", "Creating " + str(urls.size()) + " awaited request(s)")
var dldata: Array[Dictionary] = [] var dldata: Array[Dictionary] = []
@ -76,11 +114,29 @@ func _batch_awaited_request(url: String, parse_utf8: bool, method: HTTPClient.Me
logger.diagf("erm", "Waiting for request " + str(id) + " to finish") logger.diagf("erm", "Waiting for request " + str(id) + " to finish")
while !is_request_completed(id): await get_tree().create_timer(0.1, true).timeout while !is_request_completed(id): await get_tree().create_timer(0.1, true).timeout
return id return id
# +++ internal +++
## Returns a new download id.[br]
## Danger: Don't call this.
func generate_id() -> int:
var id = randi()
if list_queue.has(id) or list_active.has(id):
logger.warnf("erm", "New download id '" + str(id) + "' is already taken")
return generate_id()
logger.diagf("erm", "Generated new download id " + str(id))
return id
## Creates a new request and stores it in the queue. Returns the download id.[br]
## Warning: You'll probably not need this. Only use this function when implementing your own downloading method.
func create_request(url: String, method: HTTPClient.Method = HTTPClient.Method.METHOD_GET, headers: PackedStringArray = PackedStringArray([]), body: String = "") -> int:
logger.verbf("erm", "Creating new request\n-> URL: " + url + "\n-> Method: " + str(method) + "\nHeaders: " + str(headers.size()) + "\nBody size: " + str(body.length()) + " Characters") logger.verbf("erm", "Creating new request\n-> URL: " + url + "\n-> Method: " + str(method) + "\nHeaders: " + str(headers.size()) + "\nBody size: " + str(body.length()) + " Characters")
var id = generate_id() var id = generate_id()
list_queue.merge({ id: { "url": url, "method": method, "headers": headers, "body": body } }) list_queue.merge({ id: { "url": url, "method": method, "headers": headers, "body": body } })
return id return id
## Configures and starts a queued request.[br]
## Note: Using the [code]await[/code] keyword is required for this function.[br]
## Warning: You'll probably not need this. Only use this function when implementing your own downloading method.
func start_request(id: int, parse_utf8: bool) -> void: func start_request(id: int, parse_utf8: bool) -> void:
logger.verbf("erm", "Starting request " + str(id)) logger.verbf("erm", "Starting request " + str(id))
list_active.merge({ id: list_queue[id] }) list_active.merge({ id: list_queue[id] })
@ -100,12 +156,31 @@ func start_request(id: int, parse_utf8: bool) -> void:
add_child(download) add_child(download)
download.request(list_active[id]["url"], list_active[id]["headers"], list_active[id]["method"], list_active[id]["body"]) download.request(list_active[id]["url"], list_active[id]["headers"], list_active[id]["method"], list_active[id]["body"])
## Checks if [code]url[/code] can be used.
func is_url_allowed(url: String) -> bool:
if url.begins_with("http://"):
match(config_unsecure_requests):
CoreTypes.BlockadeLevel.BLOCK:
logger.errorf("erm", "Blocked unsecure url '" + url + "'")
return false
CoreTypes.BlockadeLevel.WARN: logger.warnf("erm", "Requesting unsecure url '" + url + "'")
CoreTypes.BlockadeLevel.IGNORE: pass
_: await logger.crashf("erm", "Invalid BlockadeLevel '" + str(config_unsecure_requests) + "'")
elif url.begins_with("https://"): pass
else:
logger.errorf("erm", "Invalid url '" + url + "'")
return false
return true
## Returns if a request has completed yet.
func is_request_completed(id: int) -> bool: return list_complete.has(id) func is_request_completed(id: int) -> bool: return list_complete.has(id)
## Cleans the request queue.
func clean_queue() -> void: func clean_queue() -> void:
logger.verbf("erm", "Cleaning request queue") logger.verbf("erm", "Cleaning request queue")
list_queue.clear() list_queue.clear()
## Cleans the completed requests list.
func clean_completed() -> void: func clean_completed() -> void:
logger.verbf("erm", "Cleaning completed requests") logger.verbf("erm", "Cleaning completed requests")
list_complete.clear() list_complete.clear()

View file

@ -21,17 +21,21 @@
## large variety of placeholders usable in [param config_format]. ## large variety of placeholders usable in [param config_format].
extends CoreBaseModule extends CoreBaseModule
# Signals
signal log_event signal log_event
# Configuration ## The minimum log level you want to be displayed.
var config_level: CoreTypes.LoggerLevel var config_level: CoreTypes.LoggerLevel
## Determines if the logger's output should be colored.
var config_colored: bool var config_colored: bool
## The template for all log messages[br]
## Available placeholders are: [code]%time%[/code], [code]%time_ms%[/code], [code]%level%[/code], [code]%color%[/code], [code]%message%[/code], [code]%source%[/code], [code]%source_raw%[/code], [code]%function%[/code] and [code]%line%[/code]
var config_format: String var config_format: String
## Determines if identation should be provided if the logger encounters a newline.
var config_newlines_override: bool var config_newlines_override: bool
## The maximum amount of characters excluding the message before newlines are no longer idented. Set to [code]-1[/code] to disable this behaviour.
var config_newlines_sizelimit: int var config_newlines_sizelimit: int
# Update configuration # +++ module +++
func _pull_config() -> void: func _pull_config() -> void:
config_level = core.config.logger_level config_level = core.config.logger_level
config_colored = core.config.logger_colored config_colored = core.config.logger_colored
@ -39,7 +43,9 @@ func _pull_config() -> void:
config_newlines_override = core.config.logger_newlines_override config_newlines_override = core.config.logger_newlines_override
config_newlines_sizelimit = core.config.logger_newlines_sizelimit config_newlines_sizelimit = core.config.logger_newlines_sizelimit
# Creates log messages # +++ logging +++
## The main logging function that does the heavy lifting.[br]
## Danger: Do not call.
func _log(level: CoreTypes.LoggerLevel, origin: String, message: String) -> void: func _log(level: CoreTypes.LoggerLevel, origin: String, message: String) -> void:
if !is_level_allowed(level): if !is_level_allowed(level):
emit_signal("log_event", false, level, origin, message, "") emit_signal("log_event", false, level, origin, message, "")
@ -82,19 +88,20 @@ func _log(level: CoreTypes.LoggerLevel, origin: String, message: String) -> void
if config_colored: print_rich(format) if config_colored: print_rich(format)
else: print(format) else: print(format)
# Check if level is allowed # +++ self explanitory +++
func is_level_allowed(level: CoreTypes.LoggerLevel) -> bool: ## Prints a diagnostic log message.
if level <= config_level: return true
else: return false
# Self explanitory
func diag(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.DIAG, origin, message) func diag(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.DIAG, origin, message)
## Prints a verbose log message.
func verb(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.VERB, origin, message) func verb(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.VERB, origin, message)
## Prints an informational log message.
func info(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.INFO, origin, message) func info(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.INFO, origin, message)
## Prints a warning log message.
func warn(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.WARN, origin, message) func warn(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.WARN, origin, message)
## Prints an error log message.
func error(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.ERROR, origin, message) func error(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.ERROR, origin, message)
## Handles crashes. Will terminate your game/application immediately.
# Built-in crash handler for CORE and applications using it ## Note: Using the [code]await[/code] keyword is required for this function.
## Danger: Don't set [code]framework_crash[/code] to [code]true[/code], thanks!
func crash(origin: String, message: String, framework_crash: bool = false) -> void: func crash(origin: String, message: String, framework_crash: bool = false) -> void:
# Collect information # Collect information
var stack: Array[Dictionary] = get_stack() var stack: Array[Dictionary] = get_stack()
@ -186,13 +193,31 @@ STACKTRACE
# Shutdown # Shutdown
await core.misc.quit_safely(69) await core.misc.quit_safely(69)
# Makes CORE development easier # Deprecated functions, will be removed soon
## Deprecated framework call
## @deprecated
func diagf(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.DIAG, core.basepath.replace("res://", "") + "src/" + origin + ".gd", message) func diagf(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.DIAG, core.basepath.replace("res://", "") + "src/" + origin + ".gd", message)
## Deprecated framework call
## @deprecated
func verbf(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.VERB, core.basepath.replace("res://", "") + "src/" + origin + ".gd", message) func verbf(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.VERB, core.basepath.replace("res://", "") + "src/" + origin + ".gd", message)
## Deprecated framework call
## @deprecated
func infof(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.INFO, core.basepath.replace("res://", "") + "src/" + origin + ".gd", message) func infof(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.INFO, core.basepath.replace("res://", "") + "src/" + origin + ".gd", message)
## Deprecated framework call
## @deprecated
func warnf(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.WARN, core.basepath.replace("res://", "") + "src/" + origin + ".gd", message) func warnf(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.WARN, core.basepath.replace("res://", "") + "src/" + origin + ".gd", message)
## Deprecated framework call
## @deprecated
func errorf(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.ERROR, core.basepath.replace("res://", "") + "src/" + origin + ".gd", message) func errorf(origin: String, message: String) -> void: _log(CoreTypes.LoggerLevel.ERROR, core.basepath.replace("res://", "") + "src/" + origin + ".gd", message)
## Deprecated framework call
## @deprecated
func crashf(origin: String, message: String) -> void: crash(core.basepath.replace("res://", "") + "src/" + origin + ".gd", message) func crashf(origin: String, message: String) -> void: crash(core.basepath.replace("res://", "") + "src/" + origin + ".gd", message)
# Returns a logger instance # +++ etc +++
## Checks if the specified log level is allowed by the current configuration.
func is_level_allowed(level: CoreTypes.LoggerLevel) -> bool:
if level <= config_level: return true
else: return false
## Returns a [class CoreLoggerInstance], which is a fancy word meaning you don't need to pass [code]origin[/code] every time you want to log something.
func get_instance(origin: String) -> CoreLoggerInstance: return CoreLoggerInstance.new(self, origin) func get_instance(origin: String) -> CoreLoggerInstance: return CoreLoggerInstance.new(self, origin)

View file

@ -28,6 +28,20 @@ var logrtl: RichTextLabel
var font_normal: Font var font_normal: Font
var font_bold: Font var font_bold: Font
# +++ module +++
func _pull_config() -> void:
background.visible = !core.config.headless and core.config.logui_enabled
background.color = core.config.logui_background_color
logrtl.add_theme_font_size_override("normal_font_size", core.config.logui_font_size)
logrtl.add_theme_font_size_override("bold_font_size", core.config.logui_font_size)
func _cleanup() -> void:
background.remove_child(logrtl)
core.sms.remove_child(background)
logrtl.queue_free()
background.queue_free()
# +++ initialization +++
func _initialize() -> void: func _initialize() -> void:
# Load fonts into memory # Load fonts into memory
font_normal = load(core.basepath + "dist/FiraCode/Regular.ttf") font_normal = load(core.basepath + "dist/FiraCode/Regular.ttf")
@ -78,18 +92,7 @@ func _ready() -> void:
# Connect log_event # Connect log_event
logger.connect("log_event", func(allowed: bool, _level: CoreTypes.LoggerLevel, _origin: String, _message: String, format: String) -> void: if allowed: logrtl.text = logrtl.text + format + "\n") logger.connect("log_event", func(allowed: bool, _level: CoreTypes.LoggerLevel, _origin: String, _message: String, format: String) -> void: if allowed: logrtl.text = logrtl.text + format + "\n")
func _cleanup() -> void: # +++ process +++
background.remove_child(logrtl)
core.sms.remove_child(background)
logrtl.queue_free()
background.queue_free()
func _pull_config() -> void:
background.visible = !core.config.headless and core.config.logui_enabled
background.color = core.config.logui_background_color
logrtl.add_theme_font_size_override("normal_font_size", core.config.logui_font_size)
logrtl.add_theme_font_size_override("bold_font_size", core.config.logui_font_size)
func _process(_delta: float) -> void: func _process(_delta: float) -> void:
if !core.config.headless: if !core.config.headless:
var window_size: Vector2i = DisplayServer.window_get_size() var window_size: Vector2i = DisplayServer.window_get_size()

View file

@ -15,36 +15,59 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
## Contains various useful functions that do not fit into other modules. ## Contains various utility functions.
## ##
## Contains various useful functions that you can use to save yourself some time ## This module contains many methods that don't fit into any other module
## programming or searching. ## and generally make your life as a developer easier.
extends CoreBaseModule extends CoreBaseModule
func quit_safely(exitcode: int = 0) -> void: # +++ data type conversion +++
logger.infof("misc", "Shutting down (code " + str(exitcode) + ")") ## Converts a number of bytes into mebibytes.[br]
logger.diagf("misc", "Waiting for log messages to be flushed") ## [br]
await get_tree().create_timer(0.25).timeout ## If [code]flatten[/code] is set to [code]true[/code], the decimal part will be discarded.
await core.cleanup()
get_tree().quit(exitcode)
@warning_ignore("integer_division") @warning_ignore("integer_division")
func byte2mib(bytes: int, flatten: bool = true) -> float: func byte2mib(bytes: int, flatten: bool = true) -> float:
if flatten: return bytes/1048576 if flatten: return bytes/1048576
return bytes/float(1048576) return bytes/float(1048576)
## Converts a number of mebibytes into bytes.[br]
## [br]
## If [code]flatten[/code] is set to [code]true[/code], the decimal part will be discarded.
func mib2byte(mib: float, flatten: bool = true) -> float: func mib2byte(mib: float, flatten: bool = true) -> float:
if flatten: return int(mib*1048576) if flatten: return int(mib*1048576)
return mib*1048576 return mib*1048576
## Converts a number of mebibytes into gibibytes.[br]
## [br]
## If [code]flatten[/code] is set to [code]true[/code], the decimal part will be discarded.
func mib2gib(mib: float, flatten: bool = true) -> float: func mib2gib(mib: float, flatten: bool = true) -> float:
if flatten: return int(mib/1024) if flatten: return int(mib/1024)
return mib/1024 return mib/1024
## Converts a number of gebibytes into mebibytes.[br]
## [br]
## If [code]flatten[/code] is set to [code]true[/code], the decimal part will be discarded.
func gib2mib(gib: float, flatten: bool = true) -> float: func gib2mib(gib: float, flatten: bool = true) -> float:
if flatten: return int(gib*1024) if flatten: return int(gib*1024)
return gib*1024 return gib*1024
# +++ type formatting +++
## Converts a string array into a normal, nicely formatted string.[br]
## [br]
## With [code]item_before[/code] and [code]item_after[/code] you can customize the lists apperance. Here's an example on how to format every item bold:
## [codeblock]
## extends Node
##
## var core: Core = get_node("/root/CORE")
## var misc: CoreBaseModule = core.misc
## var logger: CoreLoggerInstance = core.logger.get_instance("some/script.gd")
##
## func _ready() -> void:
## var array: Array[String] = ["Apples", "Bananas", "Oranges"]
##
## logger.info(misc.format_stringarray(array))
## logger.info(misc.format_stringarray(array, "[b]", "[/b]"))
## [/codeblock]
func format_stringarray(array: Array[String], item_before: String = "", item_after: String = "", separator_list: String = ", ", separator_final: String = " & ") -> String: func format_stringarray(array: Array[String], item_before: String = "", item_after: String = "", separator_list: String = ", ", separator_final: String = " & ") -> String:
var output: String = "" var output: String = ""
@ -62,6 +85,10 @@ func format_stringarray(array: Array[String], item_before: String = "", item_aft
return output return output
# +++ array conversion +++
## Converts an array into a string array.[br]
## [br]
## If an item is found that is not of type [code]String[/code], an empty array is returned.
func array_to_stringarray(array: Array) -> Array[String]: func array_to_stringarray(array: Array) -> Array[String]:
var output: Array[String] = [] var output: Array[String] = []
@ -73,6 +100,7 @@ func array_to_stringarray(array: Array) -> Array[String]:
return output return output
## Converts a string array into an array.
func stringarray_to_array(array: Array[String]) -> Array: func stringarray_to_array(array: Array[String]) -> Array:
var output: Array = [] var output: Array = []
@ -81,5 +109,27 @@ func stringarray_to_array(array: Array[String]) -> Array:
return output return output
# +++ etc +++
## Calculates the center of the child in the area of the parent.[br]
## [br]
## Example:
## [codeblock]
## extends Control
##
## var core: Core = get_node("/root/CORE")
## var misc: CoreBaseModule = core.misc
##
## func _ready() -> void:
## position = misc.center_object(get_parent().size, size)
## [/codeblock]
func get_center(parent_size: Vector2, child_size: Vector2) -> Vector2: func get_center(parent_size: Vector2, child_size: Vector2) -> Vector2:
return Vector2(parent_size.x/2-child_size.x/2, parent_size.y/2-child_size.y/2) return Vector2(parent_size.x/2-child_size.x/2, parent_size.y/2-child_size.y/2)
## Makes sure for all log messages to be flushed and that CORE is correctly cleaned up.
## Using [method SceneTree.quit] directly may cause various issues.
## Note: Using the [code]await[/code] keyword is required for this function.
func quit_safely(exitcode: int = 0) -> void:
logger.infof("misc", "Shutting down (code " + str(exitcode) + ")")
await get_tree().create_timer(0.25).timeout
await core.cleanup()
get_tree().quit(exitcode)

View file

@ -15,22 +15,34 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
## Manages scenes more efficiently. ## Manages scenes for you efficiently.
## ##
## Allows for organized scene management, making development much faster. ## Allows for organized scene management, making development much faster.
extends CoreBaseModule extends CoreBaseModule
# Objects ## Used internally for adding, managing and removing scene collections.
const scene_nodes: Array[String] = ["debug", "cutscene", "menu", "main", "background"] const scene_nodes: Array[String] = [ "debug", "cutscene", "menu", "main", "background" ]
## The 'debug' scene collection.[br]
## Danger: Don't modify this.
var scenes_debug: Node = Node.new() var scenes_debug: Node = Node.new()
## The 'cutscene' scene collection.[br]
## Danger: Don't modify this.
var scenes_cutscene: Node = Node.new() var scenes_cutscene: Node = Node.new()
## The 'menu' scene collection.[br]
## Danger: Don't modify this.
var scenes_menu: Node = Node.new() var scenes_menu: Node = Node.new()
## The 'main' scene collection.[br]
## Danger: Don't modify this.
var scenes_main: Node = Node.new() var scenes_main: Node = Node.new()
## The 'background' scene collection.[br]
## Danger: Don't modify this.
var scenes_background: Node = Node.new() var scenes_background: Node = Node.new()
# Variables ## A list of all loaded scenes[br]
## Danger: Don't modify this.
var scenes: Dictionary = {} var scenes: Dictionary = {}
# +++ module +++
func _initialize() -> void: func _initialize() -> void:
for scene in scene_nodes: for scene in scene_nodes:
get("scenes_" + scene).name = scene.to_upper() get("scenes_" + scene).name = scene.to_upper()
@ -50,7 +62,8 @@ func _pull_config() -> void:
if is_inside_tree(): logger.verbf("sms", "Removing all scenes (triggered by headless mode)") if is_inside_tree(): logger.verbf("sms", "Removing all scenes (triggered by headless mode)")
for scene in scenes: remove_scene(scene, true) for scene in scenes: remove_scene(scene, true)
# Add a scene to some scene collection # +++ scene management +++
## Adds a scene to some scene collection.
func add_scene(sname: String, sclass: Node, type: CoreTypes.SceneType) -> bool: func add_scene(sname: String, sclass: Node, type: CoreTypes.SceneType) -> bool:
if core.config.headless: return false if core.config.headless: return false
logger.verbf("sms", "Adding scene \"" + sname + "\" of type " + str(type)) logger.verbf("sms", "Adding scene \"" + sname + "\" of type " + str(type))
@ -74,7 +87,8 @@ func add_scene(sname: String, sclass: Node, type: CoreTypes.SceneType) -> bool:
scenes.merge({ sname: { "type": type, "class": sclass } }) scenes.merge({ sname: { "type": type, "class": sclass } })
return true return true
# Remove a scene from some scene collection ## Removes a scene from some scene collection.
## Danger: Don't set [code]force_remove[/code] to [code]true[/code], thanks!
func remove_scene(sname: String, force_remove: bool = false) -> bool: func remove_scene(sname: String, force_remove: bool = false) -> bool:
if core.config.headless and !force_remove: return false if core.config.headless and !force_remove: return false
if force_remove: await logger.crashf("sms", "force_remove = true is not allowed", true) if force_remove: await logger.crashf("sms", "force_remove = true is not allowed", true)
@ -102,7 +116,10 @@ func remove_scene(sname: String, force_remove: bool = false) -> bool:
scenes.erase(sname) scenes.erase(sname)
return true return true
# Return a loaded scene # +++ getters +++
## Returns a scene from some scene collection.[br]
## [br]
## Returns [code]null[/code] if no scene with that name was found.
func get_scene(sname: String) -> Node: func get_scene(sname: String) -> Node:
if core.config.headless: return null if core.config.headless: return null
match(exists(sname)): match(exists(sname)):
@ -115,7 +132,9 @@ func get_scene(sname: String) -> Node:
_: await logger.crashf("sms", "Invalid SceneType " + str(exists(sname)), true) _: await logger.crashf("sms", "Invalid SceneType " + str(exists(sname)), true)
return null return null
# Return a scene collection for scene manipulation ## Returns a scene collection node.[br]
## Useful if you want to change a child's index.[br]
## Danger: Don't change any properties of the scene collection or free it, otherwise you may cause breakage.
func get_scene_collection(type: CoreTypes.SceneType) -> Node: func get_scene_collection(type: CoreTypes.SceneType) -> Node:
if core.config.headless: return null if core.config.headless: return null
match(type): match(type):
@ -128,7 +147,7 @@ func get_scene_collection(type: CoreTypes.SceneType) -> Node:
_: await logger.crashf("sms", "Invalid SceneType " + str(type), true) _: await logger.crashf("sms", "Invalid SceneType " + str(type), true)
return null return null
# Return scenes in some scene collection ## Returns a list of all loaded scenes in some scene collection.
func get_scene_collection_list(type: CoreTypes.SceneType) -> Array[Node]: func get_scene_collection_list(type: CoreTypes.SceneType) -> Array[Node]:
var list: Array[Node] = [] var list: Array[Node] = []
for scene in scenes: for scene in scenes:
@ -136,7 +155,7 @@ func get_scene_collection_list(type: CoreTypes.SceneType) -> Array[Node]:
list.append(scenes[scene]["class"]) list.append(scenes[scene]["class"])
return list return list
# Return scene count in some scene collection ## Returns the number of loaded scenes in some scene collection.
func get_scene_collection_count(type: CoreTypes.SceneType) -> int: func get_scene_collection_count(type: CoreTypes.SceneType) -> int:
var amount: int = 0 var amount: int = 0
for scene in scenes: for scene in scenes:
@ -144,7 +163,9 @@ func get_scene_collection_count(type: CoreTypes.SceneType) -> int:
amount += 1 amount += 1
return amount return amount
# Return scene existance & scene collection ## Returns the scene collection a scene is loaded in.[br]
## [br]
## [enum CoreTypes.SceneType][code].NONE[/code] if no scene with that name was found.
func exists(sname: String) -> CoreTypes.SceneType: func exists(sname: String) -> CoreTypes.SceneType:
for scene in scenes: for scene in scenes:
if scene == sname: return scenes[scene]["type"] if scene == sname: return scenes[scene]["type"]

View file

@ -16,10 +16,22 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
extends CoreBaseModule extends CoreBaseModule
## Easy config management.
##
## Allows you to read and write configuration files with ease, without any headaches.
## Indicates if a storage file is currently open.
## Danger: Don't modify this.
var is_open: bool = false var is_open: bool = false
## The parsed data inside the storage file.
## Danger: Don't modify this.
var storage: Dictionary = {} var storage: Dictionary = {}
## The location of the storage file.
## Danger: Don't modify this.
var storage_location: String = "" var storage_location: String = ""
# +++ file management +++
## Opens a storage file into memory.
func open_storage(location: String, create_new: bool = true, sanity_check: bool = true, fail_on_sanity_check: bool = false) -> bool: func open_storage(location: String, create_new: bool = true, sanity_check: bool = true, fail_on_sanity_check: bool = false) -> bool:
if is_open: if is_open:
logger.errorf("storage", "Failed to open storage: A storage file is already open") logger.errorf("storage", "Failed to open storage: A storage file is already open")
@ -61,6 +73,7 @@ func open_storage(location: String, create_new: bool = true, sanity_check: bool
is_open = true is_open = true
return true return true
## Closes the active storage file.
func close_storage() -> bool: func close_storage() -> bool:
if !is_open: if !is_open:
logger.errorf("storage", "Failed to close storage: No storage file is open") logger.errorf("storage", "Failed to close storage: No storage file is open")
@ -70,6 +83,7 @@ func close_storage() -> bool:
is_open = false is_open = false
return true return true
## Saves the active storage file to disk.
func save_storage() -> bool: func save_storage() -> bool:
if !is_open: if !is_open:
logger.errorf("storage", "Failed to save storage: No storage file is open") logger.errorf("storage", "Failed to save storage: No storage file is open")
@ -83,6 +97,8 @@ func save_storage() -> bool:
file.close() file.close()
return true return true
# +++ config manipulation +++
## Removes all keys from the active storage file. The nuclear option basically.
func nuke_storage(autosave: bool = true) -> bool: func nuke_storage(autosave: bool = true) -> bool:
if !is_open: if !is_open:
logger.errorf("storage", "Failed to nuke storage: No storage file is open") logger.errorf("storage", "Failed to nuke storage: No storage file is open")
@ -92,6 +108,7 @@ func nuke_storage(autosave: bool = true) -> bool:
if autosave: save_storage() if autosave: save_storage()
return true return true
## Returns a storage key. Can also return a default value if unset.
func get_key(key: String, default: Variant = null) -> Variant: func get_key(key: String, default: Variant = null) -> Variant:
if !is_open: if !is_open:
logger.errorf("storage", "Failed to get key: No storage file is open") logger.errorf("storage", "Failed to get key: No storage file is open")
@ -99,6 +116,7 @@ func get_key(key: String, default: Variant = null) -> Variant:
logger.diagf("storage", "Returning storage key \"" + key + "\" (default='" + str(default) + "')") logger.diagf("storage", "Returning storage key \"" + key + "\" (default='" + str(default) + "')")
return storage.get(key, default) return storage.get(key, default)
## Updates a storage key with the specified value.
func set_key(key: String, value: Variant, overwrite: bool = true, autosave: bool = true) -> bool: func set_key(key: String, value: Variant, overwrite: bool = true, autosave: bool = true) -> bool:
if !is_open: if !is_open:
logger.errorf("storage", "Failed to set key: No storage file is open") logger.errorf("storage", "Failed to set key: No storage file is open")
@ -108,6 +126,7 @@ func set_key(key: String, value: Variant, overwrite: bool = true, autosave: bool
if autosave: save_storage() if autosave: save_storage()
return true return true
## Deletes a storage key.
func del_key(key: String, autosave: bool = true) -> bool: func del_key(key: String, autosave: bool = true) -> bool:
if !is_open: if !is_open:
logger.errof("storage", "Failed to delete key: No storage file is open") logger.errof("storage", "Failed to delete key: No storage file is open")
@ -117,6 +136,9 @@ func del_key(key: String, autosave: bool = true) -> bool:
if autosave: save_storage() if autosave: save_storage()
return true return true
## Returns the [param storage] [class Dictionary], useful for more advanced operations.[br]
## Changes are not reflected onto the [param storage] though. To save changes through this module,[br]
## pass your modified [class Dictionary to [method safe_dict].
func get_dict() -> Dictionary: func get_dict() -> Dictionary:
if !is_open: if !is_open:
logger.errorf("storage", "Failed to get dictionary: No storage file is open") logger.errorf("storage", "Failed to get dictionary: No storage file is open")
@ -124,6 +146,8 @@ func get_dict() -> Dictionary:
logger.verbf("storage", "Returning storage dictionary") logger.verbf("storage", "Returning storage dictionary")
return storage return storage
# +++ raw manipulation +++
## Saves a arbitrary dictionary as a [param storage] [class Dictionary] with sanity checking ([code]sanity_check[/code] and [code]fail_on_sanity_check[/code]).
func save_dict(dict: Dictionary, sanity_check: bool = true, fail_on_sanity_check: bool = false, autosave: bool = true) -> bool: func save_dict(dict: Dictionary, sanity_check: bool = true, fail_on_sanity_check: bool = false, autosave: bool = true) -> bool:
if !is_open: if !is_open:
logger.errorf("storage", "Failed to save dictionary: No storage file is open") logger.errorf("storage", "Failed to save dictionary: No storage file is open")
@ -145,6 +169,8 @@ func save_dict(dict: Dictionary, sanity_check: bool = true, fail_on_sanity_check
if autosave: save_storage() if autosave: save_storage()
return true return true
# +++ etc +++
## Performs sanity checks on a [class Dictionary] to determine if it can be saved and loaded using this module.
func perform_sanity_check(storage_check: Dictionary) -> Array[String]: func perform_sanity_check(storage_check: Dictionary) -> Array[String]:
logger.verbf("storage", "Performing a sanity check on some storage dictionary") logger.verbf("storage", "Performing a sanity check on some storage dictionary")
var errors: Array[String] = [] var errors: Array[String] = []