Update documentation (first commit)
This commit is contained in:
parent
7e75bc6638
commit
0ac55d4f1b
14 changed files with 264 additions and 170 deletions
|
@ -1,21 +1,23 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 1
|
sidebar_position: 0
|
||||||
|
description: Initializes and manages the framework.
|
||||||
---
|
---
|
||||||
|
|
||||||
# `CORE`
|
# `CORE`
|
||||||
The **CORE Object** is the class you use to initialize the CORE Framework.
|
The **CORE Object** is responsible for initializing, managing and serving the CORE Framework.
|
||||||
|
|
||||||
## Constants
|
## Versioning
|
||||||
### *int* <u>version_release</u>
|
### *int* <u>version_release</u>
|
||||||
CORE's release number
|
CORE's version number.
|
||||||
### *CoreTypes.VersionType* <u>version_type</u>
|
### *CoreTypes.VersionType* <u>version_type</u>
|
||||||
CORE's release type. See [`CoreTypes.VersionType`](/reference/coretypes#versiontype) for more information.
|
CORE's version type. See [`CoreTypes.VersionType`](/reference/coretypes#versiontype) for more information.
|
||||||
### *int* <u>version_typerelease</u>
|
### *int* <u>version_typerelease</u>
|
||||||
CORE's typerelease number
|
CORE's version type number. Resets on every new version and version type.
|
||||||
|
### *Array[String]* <u>modules</u> = *[ "logger", "misc", "sms", "logui", "erm", "storage" ]*
|
||||||
|
|
||||||
## Modules
|
## Modules
|
||||||
Use these to access CORE's modules.
|
Use these to access CORE's modules.
|
||||||
- [`config`](/reference/coreconfiguration) (**NEVER access this yourself. To change the configuration, use [`reload_configuration()`](#void-reload_configurationcoreconfiguration-new_config) instead**)
|
- [`config`](/reference/coreconfiguration) (**NEVER access this yourself. To change the configuration, use `reload_configuration()` instead**)
|
||||||
- [`logger`](/reference/logger)
|
- [`logger`](/reference/logger)
|
||||||
- [`misc`](/reference/misc)
|
- [`misc`](/reference/misc)
|
||||||
- `logui` (not important for developers, displays the log graphically)
|
- `logui` (not important for developers, displays the log graphically)
|
||||||
|
@ -25,40 +27,90 @@ Use these to access CORE's modules.
|
||||||
|
|
||||||
## Variables
|
## Variables
|
||||||
### *String* <u>basepath</u>
|
### *String* <u>basepath</u>
|
||||||
|
::danger[Don't modify]
|
||||||
|
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> = *{}*
|
||||||
|
### *void* <u>_ready</u>()
|
||||||
|
::danger[Don't modify]
|
||||||
|
Do not modify this.
|
||||||
|
::
|
||||||
|
Contains a list of all loaded custom modules.
|
||||||
|
### *Node* <u>custom_modules_node</u>
|
||||||
|
::danger[Don't modify]
|
||||||
|
Do not modify this.
|
||||||
|
::
|
||||||
|
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>)
|
||||||
Determines the base path, loads the configuration file and initializes all modules.
|
::danger[Don't call]
|
||||||
### *bool* <u>register_custom_module</u>(*String* <u>module_name</u>, *CoreBaseModule* <u>module_class</u>)
|
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.
|
||||||
|
### *void* <u>_ready</u>()
|
||||||
|
::danger[Don't call]
|
||||||
|
Do not call this.
|
||||||
|
::
|
||||||
|
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>()
|
||||||
|
::danger[Don't call]
|
||||||
|
Do not call this.
|
||||||
|
::
|
||||||
|
Initializes all built-in modules during the preinitialization phase.
|
||||||
|
### *void* <u>inject_modules</u>()
|
||||||
|
::danger[Don't call]
|
||||||
|
Do not call this.
|
||||||
|
::
|
||||||
|
Injects CORE's built-in modules into the SceneTree.
|
||||||
|
### *void* <u>complete_init</u>(*bool* <u>no_success_message</u> = *false*)
|
||||||
|
Waits for all built-in and custom modules to fully initialize. \
|
||||||
|
\
|
||||||
|
This ensures that all modules are fully initialized and ready for usage. \
|
||||||
|
***Not calling this function during startup may lead to runtime issues.***
|
||||||
|
### *bool* <u>register_custom_module</u>(*String* <u>module_name</u>, *String* <u>module_origin</u>, *CoreBaseModule* <u>module_class</u>)
|
||||||
Registers a custom module.
|
Registers a custom module.
|
||||||
|
|
||||||
Returns `true` if successful.
|
|
||||||
### *void* <u>unregister_custom_module</u>(*String* <u>module_name</u>)
|
### *void* <u>unregister_custom_module</u>(*String* <u>module_name</u>)
|
||||||
Unregisters a custom module.
|
Unregisters a custom module, making it no longer available.
|
||||||
### *CoreBaseModule* <u>get_custom_module</u>(*String* <u>module_name</u>)
|
### *CoreBaseModule* <u>get_custom_module</u>(*String* <u>module_name</u>)
|
||||||
Returns a registered custom module. \
|
Returns a registered custom module. \
|
||||||
Please note that you can't get CORE's builtin modules with this function.
|
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>)
|
### *void* <u>reload_configuration</u>(*CoreConfiguration* <u>new_config</u> = *CoreConfiguration.new()*)
|
||||||
Loads a new CoreConfiguration class and applies it's settings.
|
Loads a (new) configuration object and applies it to all modules.
|
||||||
|
### *void* <u>apply_configuration</u>()
|
||||||
|
::danger[Don't call]
|
||||||
|
Do not call this.
|
||||||
|
::
|
||||||
|
Applies the a configuration.
|
||||||
|
### *void* <u>cleanup</u>()
|
||||||
|
Makes sure that CORE does not leak memory on shutdown/unload. \
|
||||||
|
Unloads all custom modules, built-in modules, frees any of CORE's classes and lastly itself.
|
||||||
### *bool* <u>is_devmode</u>()
|
### *bool* <u>is_devmode</u>()
|
||||||
Returns the development mode status.
|
Returns if the CORE Framework is in development mode.
|
||||||
### *String* <u>get_format_string</u>(*String* <u>string</u>)
|
### *String* <u>get_format_string</u>(*String* <u>string</u>)
|
||||||
Replaces placeholders with human-friendly strings \
|
Replaces placeholders with human-friendly strings. \
|
||||||
You can use the following placeholders:
|
You can use the following placeholders:
|
||||||
- `%release%`
|
- `%version%`
|
||||||
Returns the release number.
|
Returns the version number.
|
||||||
- `%release_type%`
|
- `%version_type%`
|
||||||
Returns the typerelease number
|
Returns the version type number
|
||||||
- `%release_semantic%`
|
- `%version_semantic%`
|
||||||
Returns the result of [`get_version_semantic()`](#arrayint-get_version_semantic), example *5.2.3*
|
Returns the result of `get_version_semantic()`, example *5.2.3*
|
||||||
- `%type%`
|
- `%version_type%`
|
||||||
Returns the release type as a word, for example *Release Candidate*
|
Returns the version type as a word, for example *Release Candidate*
|
||||||
- `%type_technical%`
|
- `%version_type_technical%`
|
||||||
Returns the release type as one or two lowercase letters, for example *rc*
|
Returns the version type as one or two lowercase letters, for example *rc*
|
||||||
- `%devmode%`
|
- `%devmode%`
|
||||||
Returns the development mode status
|
Returns the development mode status
|
||||||
- `%headless%`
|
- `%headless%`
|
||||||
Returns the headless mode status
|
Returns the headless mode status
|
||||||
|
- `%custommodules%`
|
||||||
|
Returns if custom module support is enabled
|
||||||
### *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 release number, the second integer contains the release type (0 for alpha, 1 for beta, 2 for rc and 3 for release) and the last integer contains the typerelease 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>()
|
||||||
|
::danger[Don't call]
|
||||||
|
Do not call this.
|
||||||
|
::
|
||||||
|
Determines CORE's installation/base path.
|
||||||
|
|
30
docs/docs/reference/corebasemodule.md
Normal file
30
docs/docs/reference/corebasemodule.md
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 3
|
||||||
|
description: Template for CORE modules
|
||||||
|
---
|
||||||
|
|
||||||
|
# `CoreBaseModule`
|
||||||
|
Provides a basic template and a common foundation for building CORE modules. \
|
||||||
|
It provides common functions and variables used in all CORE modules.
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
### *Core* <u>core</u>
|
||||||
|
Contains a reference to the [CORE Object](/reference/core).
|
||||||
|
### *CoreBaseModule* <u>logger</u> = *core.logger*
|
||||||
|
Set to CORE's logger implementation.
|
||||||
|
### *CoreLoggerInstance* <u>loggeri</u>
|
||||||
|
Set to a logger instance with the path you supplied to `core.register_custom_module`. You should use this over `logger`.
|
||||||
|
### *bool* <u>initialized</u> = *false*
|
||||||
|
Marks a module as fully initialized and ready. **Don't forget to set this!**
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
### *void* <u>_initialize</u>()
|
||||||
|
CORE's replacement for `Object._init` and `Node._ready`. \
|
||||||
|
It's **strongly** recommended to initialize your module here or stuff might break.
|
||||||
|
### *void* <u>_cleanup</u>()
|
||||||
|
Called when CORE is about to cleanup. \
|
||||||
|
Use this function to remove any children from the SceneTree and free any nodes. \
|
||||||
|
If not done you might cause a memory leak.
|
||||||
|
### *void* <u>_pull_config</u>()
|
||||||
|
Called after CORE's configuration got updated. \
|
||||||
|
Probably useless to your module, unless you want to modify another module's settings.
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 6
|
sidebar_position: 1
|
||||||
---
|
---
|
||||||
|
|
||||||
# `CoreConfiguration`
|
# `CoreConfiguration`
|
||||||
|
@ -17,6 +17,7 @@ This will not enable the development mode automatically, only if you're developi
|
||||||
Allows debugging functionality if set to `true`, or not if set to `false`.
|
Allows debugging functionality if set to `true`, or not if set to `false`.
|
||||||
### *bool* <u>custom_modules</u> = *false*
|
### *bool* <u>custom_modules</u> = *false*
|
||||||
Allows or disallows custom modules.
|
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?
|
I don't have to explain this, do I?
|
||||||
|
@ -37,6 +38,7 @@ 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 than can appear before `%message%` before newlines won't be overriden. Setting this variable to `-1` disables this behaviour.
|
||||||
|
|
||||||
## LogUI
|
## LogUI
|
||||||
### *bool* <u>logui_enabled</u> = *true*
|
### *bool* <u>logui_enabled</u> = *true*
|
||||||
Determines if [`LogUI`](/terminology#logui) should be visible or not.
|
Determines if [`LogUI`](/terminology#logui) should be visible or not.
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 5
|
sidebar_position: 2
|
||||||
|
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>
|
### <u>VersionType</u>{ RELEASE, RELEASECANDIDATE, BETA, ALPHA }
|
||||||
RELEASE, RELEASECANDIDATE, BETA, ALPHA
|
Available version types, following the StarOpenSource Versioning Specification (SOSVS) version 1.
|
||||||
### <u>LoggerLevel</u>
|
### <u>LoggerLevel</u>{ NONE, ERROR, WARN, INFO, VERB, DIAG }
|
||||||
NONE, ERROR, WARN, INFO, VERB, DIAG
|
Available log levels, followingthe StarOpenSource Logging Specification (SOSLS) version 1.
|
||||||
### <u>SceneType</u>
|
### <u>SceneType</u>{ NONE, DEBUG, CUTSCENE, MENU, MAIN, BACKGROUND }
|
||||||
NONE, DEBUG, CUTSCENE, MENU, MAIN, BACKGROUND
|
Available scene types.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 2
|
sidebar_position: 4
|
||||||
---
|
---
|
||||||
|
|
||||||
# `Logger`
|
# `Logger`
|
||||||
|
|
|
@ -1,21 +1,33 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 3
|
sidebar_position: 5
|
||||||
|
description: Passes `origin` for you.
|
||||||
---
|
---
|
||||||
|
|
||||||
# `LoggerInstance`
|
# `LoggerInstance`
|
||||||
Passes <u>origin</u> for you.
|
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 ;)
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
### *CoreBaseModule* <u>logger</u>
|
||||||
|
Reference to CORE's logger module.
|
||||||
|
### *String* <u>origin</u>
|
||||||
|
The origin argument.
|
||||||
|
|
||||||
## Functions
|
## Functions
|
||||||
|
### *void* <u>_init</u>(*CoreBaseModule* <u>logger_new</u>, *String* <u>origin_new</u>)
|
||||||
|
The instance constructor.
|
||||||
### *void* <u>diag</u>(*String* <u>message</u>)
|
### *void* <u>diag</u>(*String* <u>message</u>)
|
||||||
Prints a diagnostic message
|
Prints a diagnostic message.
|
||||||
### *void* <u>verb</u>(*String* <u>message</u>)
|
### *void* <u>verb</u>(*String* <u>message</u>)
|
||||||
Prints a verbose message
|
Prints a verbose message.
|
||||||
### *void* <u>info</u>(*String* <u>message</u>)
|
### *void* <u>info</u>(*String* <u>message</u>)
|
||||||
Prints an informational message
|
Prints an informational message.
|
||||||
### *void* <u>warn</u>(*String* <u>message</u>)
|
### *void* <u>warn</u>(*String* <u>message</u>)
|
||||||
Prints a warning message
|
Prints a warning message.
|
||||||
### *void* <u>error</u>(*String* <u>message</u>)
|
### *void* <u>error</u>(*String* <u>message</u>)
|
||||||
Prints an error message
|
Prints an error message.
|
||||||
### *void* <u>crash</u>(*String* <u>message</u>)
|
### *void* <u>crash</u>(*String* <u>message</u>)
|
||||||
:::note[Awaiting required]
|
:::note[Awaiting required]
|
||||||
Using the `await` keyword is required for this function.
|
Using the `await` keyword is required for this function.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
sidebar_position: 4
|
sidebar_position: 6
|
||||||
---
|
---
|
||||||
|
|
||||||
# `Miscellaneous`
|
# `Miscellaneous`
|
||||||
|
|
|
@ -9,7 +9,9 @@ You don't know a word? Look it up here.
|
||||||
The **CORE Object** is the class you use to initialize the CORE Framework.
|
The **CORE Object** is the class you use to initialize the CORE Framework.
|
||||||
## `Log UI`
|
## `Log UI`
|
||||||
Displays the log/console output graphically in the background.
|
Displays the log/console output graphically in the background.
|
||||||
|
## `ERM`
|
||||||
|
Stands for **Easy Request Maker** and allows you to download stuff.
|
||||||
## `EDL`
|
## `EDL`
|
||||||
Stands for **Easy DownLoader** and allows you to download stuff.
|
The old name for the [`ERM`](#erm) module, which was called `Easy DownLoader` previously.
|
||||||
## `SMS`
|
## `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.
|
||||||
|
|
|
@ -15,23 +15,23 @@
|
||||||
"typecheck": "tsc"
|
"typecheck": "tsc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.1.1",
|
"@docusaurus/core": "3.2.1",
|
||||||
"@docusaurus/plugin-client-redirects": "^3.1.1",
|
"@docusaurus/plugin-client-redirects": "^3.2.1",
|
||||||
"@docusaurus/plugin-content-docs": "^3.1.1",
|
"@docusaurus/plugin-content-docs": "^3.2.1",
|
||||||
"@docusaurus/plugin-sitemap": "^3.1.1",
|
"@docusaurus/plugin-sitemap": "^3.2.1",
|
||||||
"@docusaurus/preset-classic": "3.1.1",
|
"@docusaurus/preset-classic": "3.2.1",
|
||||||
"@mdx-js/react": "^3.0.0",
|
"@mdx-js/react": "^3.0.1",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.1.0",
|
||||||
"prism-react-renderer": "^2.3.0",
|
"prism-react-renderer": "^2.3.1",
|
||||||
"react": "^18.0.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.0.0"
|
"react-dom": "^18.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "3.1.1",
|
"@docusaurus/module-type-aliases": "3.2.1",
|
||||||
"@docusaurus/tsconfig": "3.1.1",
|
"@docusaurus/tsconfig": "3.2.1",
|
||||||
"@docusaurus/types": "3.1.1",
|
"@docusaurus/types": "3.2.1",
|
||||||
"@types/node": "^20.11.0",
|
"@types/node": "^20.12.5",
|
||||||
"typescript": "~5.2.2"
|
"typescript": "~5.4.4"
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"production": [
|
"production": [
|
||||||
|
|
|
@ -22,25 +22,22 @@
|
||||||
extends Node
|
extends Node
|
||||||
class_name CoreBaseModule
|
class_name CoreBaseModule
|
||||||
|
|
||||||
## Contains a reference to the CORE Object[br]
|
## Contains a reference to the CORE Object.
|
||||||
## [br]
|
|
||||||
## Set before loading the module into the SceneTree.
|
|
||||||
var core: Core
|
var core: Core
|
||||||
## Reference to CORE's logger implementation.[br]
|
## Set to CORE's logger implementation.
|
||||||
## [br]
|
|
||||||
## Will be set before [method Node._ready]
|
|
||||||
@onready var logger: CoreBaseModule = core.logger
|
@onready var logger: CoreBaseModule = core.logger
|
||||||
## Reference to a matching [class CoreLoggerInstance].
|
## Set to a [class CoreLoggerInstance] with the path you supplied to [method Core.register_custom_module]. You should use this over [code]logger[/code].
|
||||||
var loggeri: CoreLoggerInstance
|
var loggeri: CoreLoggerInstance
|
||||||
## Marks a module as fully initialized and ready.
|
## Marks a module as fully initialized and ready. **Don't forget to set this!**
|
||||||
var initialized: bool = false
|
var initialized: bool = false
|
||||||
|
|
||||||
## CORE's replacement for [method Object._init] and [method Node._ready]
|
## CORE's replacement for [method Object._init] and [method Node._ready].
|
||||||
## It's [b]strongly[/b] recommended to initialize your module here.
|
## It's [b]strongly[/b] recommended to initialize your module here or stuff might break.
|
||||||
func _initialize() -> void: initialized = true
|
func _initialize() -> void: initialized = true
|
||||||
## Called when CORE is about to cleanup
|
## Called when CORE is about to cleanup.[br]
|
||||||
## Use this function to free any children
|
## Use this function to remove any children from the SceneTree and free any nodes.[br]
|
||||||
|
## If not done you might cause a memory leak.
|
||||||
func _cleanup() -> void: pass
|
func _cleanup() -> void: pass
|
||||||
## Called by [method Core.apply_configuration].
|
## Called after CORE's configuration got updated.[br]
|
||||||
## This should be used to update your module configuration.
|
## Probably useless to your module, unless you want to modify another module's settings.
|
||||||
func _pull_config() -> void: pass
|
func _pull_config() -> void: pass
|
||||||
|
|
|
@ -8,7 +8,7 @@ extends Node
|
||||||
class_name CoreConfiguration
|
class_name CoreConfiguration
|
||||||
|
|
||||||
@export_category("Global")
|
@export_category("Global")
|
||||||
## Controls CORE's functionality.
|
## Controls CORE's functionality.[br]
|
||||||
## Renders GUI-related modules useless when set to [code]false[/code], which is the recommended behaviour on servers. For CORE's full functionality, set this to [code]true[/code].
|
## Renders GUI-related modules useless when set to [code]false[/code], which is the recommended behaviour on servers. For CORE's full functionality, set this to [code]true[/code].
|
||||||
@export var headless: bool
|
@export var headless: bool
|
||||||
## Allows debugging functionality if set to [code]true[/code], or not if set to [code]false[/code].[br]
|
## Allows debugging functionality if set to [code]true[/code], or not if set to [code]false[/code].[br]
|
||||||
|
@ -24,7 +24,7 @@ class_name CoreConfiguration
|
||||||
@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 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]
|
||||||
@export var logger_format: String
|
@export var logger_format: String
|
||||||
## This example should make it clear, what this does:
|
## This example should make it clear, what this does:[br]
|
||||||
## [codeblock]
|
## [codeblock]
|
||||||
## logger_newlines_override = true:
|
## logger_newlines_override = true:
|
||||||
## [09:47:00] [INFO Test.gd:69] This is a test message...
|
## [09:47:00] [INFO Test.gd:69] This is a test message...
|
||||||
|
|
|
@ -24,23 +24,26 @@
|
||||||
extends Node
|
extends Node
|
||||||
class_name CoreLoggerInstance
|
class_name CoreLoggerInstance
|
||||||
|
|
||||||
## Class name
|
## Reference to CORE's logger module.
|
||||||
var logger: CoreBaseModule
|
var logger: CoreBaseModule
|
||||||
|
## The origin argument.
|
||||||
var origin: String
|
var origin: String
|
||||||
|
|
||||||
|
## The instance constructor.
|
||||||
func _init(logger_new: CoreBaseModule, origin_new: String) -> void:
|
func _init(logger_new: CoreBaseModule, origin_new: String) -> void:
|
||||||
logger = logger_new
|
logger = logger_new
|
||||||
origin = origin_new
|
origin = origin_new
|
||||||
|
|
||||||
## Prints a diagnostic message
|
## Prints a diagnostic message.
|
||||||
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 a 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 a 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.
|
||||||
func crash(message: String) -> void: await logger.crash(origin, message)
|
func crash(message: String) -> void: await logger.crash(origin, message)
|
||||||
|
|
|
@ -19,9 +19,9 @@
|
||||||
extends Node
|
extends Node
|
||||||
class_name CoreTypes
|
class_name CoreTypes
|
||||||
|
|
||||||
## Available version types, following the StarOpenSource Versioning Specification (SOSVS) version 1
|
## Available version types, following the StarOpenSource Versioning Specification (SOSVS) version 1.
|
||||||
enum VersionType { RELEASE, RELEASECANDIDATE, BETA, ALPHA }
|
enum VersionType { RELEASE, RELEASECANDIDATE, BETA, ALPHA }
|
||||||
## Available log levels, followingthe StarOpenSource Logging Specification (SOSLS) version 1
|
## Available log levels, followingthe StarOpenSource Logging Specification (SOSLS) version 1.
|
||||||
enum LoggerLevel { NONE, ERROR, WARN, INFO, VERB, DIAG }
|
enum LoggerLevel { NONE, ERROR, WARN, INFO, VERB, DIAG }
|
||||||
## Available scene types
|
## Available scene types.
|
||||||
enum SceneType { NONE, DEBUG, CUTSCENE, MENU, MAIN, BACKGROUND }
|
enum SceneType { NONE, DEBUG, CUTSCENE, MENU, MAIN, BACKGROUND }
|
||||||
|
|
161
src/core.gd
161
src/core.gd
|
@ -18,46 +18,50 @@
|
||||||
## Initializes and manages the framework.
|
## Initializes and manages the framework.
|
||||||
##
|
##
|
||||||
## The [b]CORE Object[/b] is responsible for initializing, managing and
|
## The [b]CORE Object[/b] is responsible for initializing, managing and
|
||||||
## serving the CORE Framework to the developer.
|
## serving the CORE Framework.
|
||||||
extends Node
|
extends Node
|
||||||
class_name Core
|
class_name Core
|
||||||
|
|
||||||
# Constants
|
# Versioning
|
||||||
## The version number
|
## The version number
|
||||||
const version_version: int = 1
|
const version_version: int = 1
|
||||||
## The version type
|
## The version type. See [enum CoreTypes.VersionType] for more information.
|
||||||
const version_type: CoreTypes.VersionType = CoreTypes.VersionType.BETA
|
const version_type: CoreTypes.VersionType = CoreTypes.VersionType.BETA
|
||||||
## The version type number. Resets on every new version and version type.
|
## The version type number. Resets on every new version and version type.
|
||||||
const version_typerelease: int = 4
|
const version_typerelease: int = 6
|
||||||
|
|
||||||
# Modules
|
# Modules
|
||||||
|
## Used internally for loading, managing and unloading modules.
|
||||||
const modules: Array[String] = [ "logger", "misc", "sms", "logui", "erm", "storage" ]
|
const modules: Array[String] = [ "logger", "misc", "sms", "logui", "erm", "storage" ]
|
||||||
## Use this to access CORE's logging implementation.
|
## CORE's configuration object.[br]
|
||||||
|
## [b]NEVER access this yourself! To change the configuration use [method reload_configuration] instead.[/b]
|
||||||
|
var config: CoreConfiguration
|
||||||
|
## The 'Logger' module
|
||||||
var logger: CoreBaseModule
|
var logger: CoreBaseModule
|
||||||
## Use this to access various useful functions.
|
## The 'Miscellaneous' module
|
||||||
var misc: CoreBaseModule
|
var misc: CoreBaseModule
|
||||||
## Use this to access the scene management system.
|
## The 'Scene Management System' module
|
||||||
var sms: CoreBaseModule
|
var sms: CoreBaseModule
|
||||||
## Use this to access the graphical log. Serves no importance to you (probably).
|
## The 'Log UI' module. Not important for you, it just displays the log graphically :3
|
||||||
var logui: CoreBaseModule
|
var logui: CoreBaseModule
|
||||||
## Use this to access CORE's builtin HTTP request maker.
|
## The 'Easy Request Maker' module (formerly 'Easy DownLoader')
|
||||||
var erm: CoreBaseModule
|
var erm: CoreBaseModule
|
||||||
## Use this to access configuration and settings files easily.
|
## The 'Storage' module
|
||||||
var storage: CoreBaseModule
|
var storage: CoreBaseModule
|
||||||
|
|
||||||
# Variables
|
# /etc/
|
||||||
## Contains CORE's load path
|
## Stores the path to CORE's installation directory.[br]
|
||||||
|
## Danger: Don't modify this.
|
||||||
var basepath: String
|
var basepath: String
|
||||||
## Holds the configuration[br]
|
## Contains a list of all loaded custom modules.[br]
|
||||||
## [br]
|
## Danger: Don't modify this.
|
||||||
## [b]NEVER access this yourself. To change the configuration file, use [method Core.reload_configuration] instead.[/b]
|
|
||||||
var config: CoreConfiguration
|
|
||||||
## Contains all loaded custom modules.
|
|
||||||
var custom_modules: Dictionary = {}
|
var custom_modules: Dictionary = {}
|
||||||
## Contains the custom modules node.
|
## Contains the node holding all custom modules as children.[br]
|
||||||
|
## Danger: Don't modify this.
|
||||||
var custom_modules_node: Node
|
var custom_modules_node: Node
|
||||||
|
|
||||||
# Preinitialization
|
# +++ initialization +++
|
||||||
|
## Handles the preinitialization part. Does stuff like checking the engine version, loading the config and loading all modules into memory.
|
||||||
func _init(new_config: CoreConfiguration = CoreConfiguration.new()) -> void:
|
func _init(new_config: CoreConfiguration = CoreConfiguration.new()) -> void:
|
||||||
name = "CORE"
|
name = "CORE"
|
||||||
if !check_godot_version(): return
|
if !check_godot_version(): return
|
||||||
|
@ -67,32 +71,15 @@ func _init(new_config: CoreConfiguration = CoreConfiguration.new()) -> void:
|
||||||
initialize_modules()
|
initialize_modules()
|
||||||
apply_configuration()
|
apply_configuration()
|
||||||
|
|
||||||
# Initialization
|
## Handles the initialization part. Injects the builtin modules into the SceneTree and makes sure custom modules can be loaded properly.[br]
|
||||||
|
## Danger: Don't call this.
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
inject_modules()
|
inject_modules()
|
||||||
custom_modules_node.name = "Custom Modules"
|
custom_modules_node.name = "Custom Modules"
|
||||||
add_child(custom_modules_node)
|
add_child(custom_modules_node)
|
||||||
|
|
||||||
# Cleanup
|
## Initializes all built-in modules during the preinitialization phase.[br]
|
||||||
# Particularily useful during testing to cleanup stuff, or if you want to do some stupid stuff with CORE during runtime
|
## Danger: Don't call this.
|
||||||
func cleanup() -> void:
|
|
||||||
logger.infof("core", "Cleaning up")
|
|
||||||
config.queue_free()
|
|
||||||
var modules_reverse: Array[String] = modules.duplicate()
|
|
||||||
modules_reverse.reverse()
|
|
||||||
for module in modules_reverse:
|
|
||||||
await get(module)._cleanup()
|
|
||||||
get(module).loggeri.queue_free()
|
|
||||||
get(module).queue_free()
|
|
||||||
for module in custom_modules_node.get_children(): unregister_custom_module(module.name)
|
|
||||||
remove_child(custom_modules_node)
|
|
||||||
custom_modules_node.queue_free()
|
|
||||||
queue_free()
|
|
||||||
|
|
||||||
# Initialize modules
|
|
||||||
## Initializes all modules during the first initialization phase.[br]
|
|
||||||
## [br]
|
|
||||||
## [b]NEVER call this yourself! You will break everything and risk a crash![/b]
|
|
||||||
func initialize_modules() -> void:
|
func initialize_modules() -> void:
|
||||||
for module in modules:
|
for module in modules:
|
||||||
set(module, CoreBaseModule.new())
|
set(module, CoreBaseModule.new())
|
||||||
|
@ -102,18 +89,15 @@ func initialize_modules() -> void:
|
||||||
get(module).loggeri = logger.get_instance(basepath.replace("res://", "") + "src/" + module + ".gd")
|
get(module).loggeri = logger.get_instance(basepath.replace("res://", "") + "src/" + module + ".gd")
|
||||||
get(module)._initialize()
|
get(module)._initialize()
|
||||||
|
|
||||||
# Inject modules into the SceneTree
|
|
||||||
## Injects CORE's builtin modules into the SceneTree.[br]
|
## Injects CORE's builtin modules into the SceneTree.[br]
|
||||||
## [br]
|
## Danger: Don't call this.
|
||||||
## [b]NEVER call this yourself! You will break everything and risk a crash![/b]
|
|
||||||
func inject_modules() -> void: for module in modules: add_child(get(module))
|
func inject_modules() -> void: for module in modules: add_child(get(module))
|
||||||
|
|
||||||
# Wait for all modules to be fully initialized
|
## Waits for all modules to fully initialize.[br]
|
||||||
## Wait for all builtin modules to be fully initialized.[br]
|
|
||||||
## [br]
|
## [br]
|
||||||
## This ensures that all of CORE's builtin modules are fully initialized and ready.
|
## This ensures that all modules are fully initialized and ready for usage.[br]
|
||||||
## [b]Not calling this function during startup may lead to runtime issues.[/b]
|
## [i][b]Not calling this function during startup may lead to runtime issues.[/b][/i]
|
||||||
func complete_init(no_success: bool = false) -> void:
|
func complete_init(no_success_message: bool = false) -> void:
|
||||||
var modsinit_builtin: Array[String] = ["workaround"]
|
var modsinit_builtin: Array[String] = ["workaround"]
|
||||||
var modsinit_custom: Array[String] = ["workaround"]
|
var modsinit_custom: Array[String] = ["workaround"]
|
||||||
|
|
||||||
|
@ -138,9 +122,9 @@ func complete_init(no_success: bool = false) -> void:
|
||||||
|
|
||||||
# Initialization complete
|
# Initialization complete
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
if !no_success: logger.infof("core", "Initialized CORE successfully")
|
if !no_success_message: logger.infof("core", "Initialized CORE successfully")
|
||||||
|
|
||||||
# Registers a custom module
|
# +++ custom module support +++
|
||||||
## Registers a new custom module.
|
## Registers a new custom module.
|
||||||
func register_custom_module(module_name: String, module_origin: String, module_class: CoreBaseModule) -> bool:
|
func register_custom_module(module_name: String, module_origin: String, module_class: CoreBaseModule) -> bool:
|
||||||
logger.verbf("core", "Registering new custom module \"" + module_name + "\"")
|
logger.verbf("core", "Registering new custom module \"" + module_name + "\"")
|
||||||
|
@ -164,8 +148,7 @@ func register_custom_module(module_name: String, module_origin: String, module_c
|
||||||
module_class._pull_config()
|
module_class._pull_config()
|
||||||
return true
|
return true
|
||||||
|
|
||||||
# Unregisters a custom module
|
## Unregisters a custom module, making it no longer available.
|
||||||
## Unregisters a custom module, making it no longer function.
|
|
||||||
func unregister_custom_module(module_name: String) -> void:
|
func unregister_custom_module(module_name: String) -> void:
|
||||||
logger.verbf("core", "Unregistering custom module \"" + module_name + "\"")
|
logger.verbf("core", "Unregistering custom module \"" + module_name + "\"")
|
||||||
if !custom_modules.has(module_name):
|
if !custom_modules.has(module_name):
|
||||||
|
@ -178,8 +161,8 @@ func unregister_custom_module(module_name: String) -> void:
|
||||||
custom_modules.erase(module_name)
|
custom_modules.erase(module_name)
|
||||||
module.queue_free()
|
module.queue_free()
|
||||||
|
|
||||||
# Returns a custom module
|
## Returns a registered custom module.[br]
|
||||||
## Returns a loaded custom module for access.
|
## Please note that you can't get CORE's built-in modules with this function.
|
||||||
func get_custom_module(module_name: String) -> CoreBaseModule:
|
func get_custom_module(module_name: String) -> CoreBaseModule:
|
||||||
logger.diagf("core", "Getting custom module \"" + module_name + "\"")
|
logger.diagf("core", "Getting custom module \"" + module_name + "\"")
|
||||||
if !custom_modules.has(module_name):
|
if !custom_modules.has(module_name):
|
||||||
|
@ -187,8 +170,8 @@ func get_custom_module(module_name: String) -> CoreBaseModule:
|
||||||
return null
|
return null
|
||||||
return custom_modules[module_name]
|
return custom_modules[module_name]
|
||||||
|
|
||||||
# (Re-)Load configuration
|
# +++ configuration +++
|
||||||
## Loads a (new) configuration file and applies it to all modules.
|
## Loads a (new) configuration object and applies it to all modules.
|
||||||
func reload_configuration(new_config: CoreConfiguration = CoreConfiguration.new()) -> void:
|
func reload_configuration(new_config: CoreConfiguration = CoreConfiguration.new()) -> void:
|
||||||
var initialized = config != null
|
var initialized = config != null
|
||||||
if initialized: logger.verbf("core", "Reloading CORE's configuration")
|
if initialized: logger.verbf("core", "Reloading CORE's configuration")
|
||||||
|
@ -199,10 +182,8 @@ func reload_configuration(new_config: CoreConfiguration = CoreConfiguration.new(
|
||||||
if initialized: logger.verbf("core", "Overrode configuration (development mode)")
|
if initialized: logger.verbf("core", "Overrode configuration (development mode)")
|
||||||
if initialized: apply_configuration()
|
if initialized: apply_configuration()
|
||||||
|
|
||||||
# Call _pull_config() functions
|
## Applies the a configuration.[br]
|
||||||
## Applies the newly applied configuration.[br]
|
## Danger: Don't call this.
|
||||||
## [br]
|
|
||||||
## [b]NEVER call this yourself unless you know what you are doing![/b]
|
|
||||||
func apply_configuration() -> void:
|
func apply_configuration() -> void:
|
||||||
logger.verbf("core", "Applying configuration")
|
logger.verbf("core", "Applying configuration")
|
||||||
if is_devmode(): logger.warnf("core", "The CORE Framework is in development mode. Here be dragons!")
|
if is_devmode(): logger.warnf("core", "The CORE Framework is in development mode. Here be dragons!")
|
||||||
|
@ -216,20 +197,37 @@ func apply_configuration() -> void:
|
||||||
logger.diagf("core", "Updating configuration for custom module \"" + module.name + "\"")
|
logger.diagf("core", "Updating configuration for custom module \"" + module.name + "\"")
|
||||||
module._pull_config()
|
module._pull_config()
|
||||||
|
|
||||||
# Return development mode status
|
# +++ etc ++
|
||||||
|
## Makes sure that CORE does not leak memory on shutdown/unload.[br]
|
||||||
|
## Unloads all custom modules, built-in modules, frees any of CORE's classes and lastly itself.
|
||||||
|
func cleanup() -> void:
|
||||||
|
logger.infof("core", "Cleaning up")
|
||||||
|
config.queue_free()
|
||||||
|
var modules_reverse: Array[String] = modules.duplicate()
|
||||||
|
modules_reverse.reverse()
|
||||||
|
for module in modules_reverse:
|
||||||
|
await get(module)._cleanup()
|
||||||
|
get(module).loggeri.queue_free()
|
||||||
|
get(module).queue_free()
|
||||||
|
for module in custom_modules_node.get_children(): unregister_custom_module(module.name)
|
||||||
|
remove_child(custom_modules_node)
|
||||||
|
custom_modules_node.queue_free()
|
||||||
|
queue_free()
|
||||||
|
|
||||||
## Returns if the CORE Framework is in development mode.
|
## Returns if the CORE Framework is in development mode.
|
||||||
func is_devmode() -> bool:
|
func is_devmode() -> bool:
|
||||||
return config.debugging and basepath == "res://" and OS.is_debug_build()
|
return config.debugging and basepath == "res://" and OS.is_debug_build()
|
||||||
|
|
||||||
# Replaces variables with human-friendly strings
|
## Replaces placeholders with human-friendly strings.[br]
|
||||||
## Replaces placeholders with human-friendly strings You can use the following placeholders:[br]
|
## You can use the following placeholders:[br]
|
||||||
## - [code]%release%[/code]: Returns the release number.[br]
|
## - [code]%version%[/code]: Returns the version number.[br]
|
||||||
## - [code]%release_type%[/code]: Returns the typerelease number[br]
|
## - [code]%version_type%[/code]: Returns the version type number[br]
|
||||||
## - [code]%release_semantic%[/code]: Returns the result of [method Core.get_version_semantic], example [i]5.2.3[/i][br]
|
## - [code]%version_semantic%[/code]: Returns the result of [method Core.get_version_semantic], example [i]5.2.3[/i][br]
|
||||||
## - [code]%type%[/code]: Returns the release type as a word, for example [i]Release Candidate[/i][br]
|
## - [code]%version_type%[/code]: Returns the version type as a word, for example [i]Release Candidate[/i][br]
|
||||||
## - [code]%type_technical%[/code]: Returns the release type as one or two lowercase letters, for example [i]rc[/i][br]
|
## - [code]%version_type_technical%[/code]: Returns the version type as one or two lowercase letters, for example [i]rc[/i][br]
|
||||||
## - [code]%devmode%[/code]: Returns the development mode status[br]
|
## - [code]%devmode%[/code]: Returns the development mode status[br]
|
||||||
## - [code]%headless%[/code]: Returns the headless mode status
|
## - [code]%headless%[/code]: Returns the headless mode status[br]
|
||||||
|
## - [code]%custommodules%[/code]: Returns if custom module support is enabled
|
||||||
func get_formatted_string(string: String) -> String:
|
func get_formatted_string(string: String) -> String:
|
||||||
# Version strings
|
# Version strings
|
||||||
string = string.replace("%version%", str(version_version))
|
string = string.replace("%version%", str(version_version))
|
||||||
|
@ -238,17 +236,17 @@ func get_formatted_string(string: String) -> String:
|
||||||
string = string.replace("%version_semantic%", str(semantic_version[0]) + "." + str(semantic_version[1]) + "." + str(semantic_version[2]))
|
string = string.replace("%version_semantic%", str(semantic_version[0]) + "." + str(semantic_version[1]) + "." + str(semantic_version[2]))
|
||||||
match(version_type):
|
match(version_type):
|
||||||
CoreTypes.VersionType.RELEASE:
|
CoreTypes.VersionType.RELEASE:
|
||||||
string = string.replace("%type%", "Release")
|
string = string.replace("%version_type%", "Release")
|
||||||
string = string.replace("%type_technical%", "r")
|
string = string.replace("%version_type_technical%", "r")
|
||||||
CoreTypes.VersionType.RELEASECANDIDATE:
|
CoreTypes.VersionType.RELEASECANDIDATE:
|
||||||
string = string.replace("%type%", "Release Candidate")
|
string = string.replace("%version_type%", "Release Candidate")
|
||||||
string = string.replace("%type_technical%", "rc")
|
string = string.replace("%version_type_technical%", "rc")
|
||||||
CoreTypes.VersionType.BETA:
|
CoreTypes.VersionType.BETA:
|
||||||
string = string.replace("%type%", "Beta")
|
string = string.replace("%version_type%", "Beta")
|
||||||
string = string.replace("%type_technical%", "b")
|
string = string.replace("%version_type_technical%", "b")
|
||||||
CoreTypes.VersionType.ALPHA:
|
CoreTypes.VersionType.ALPHA:
|
||||||
string = string.replace("%type%", "Alpha")
|
string = string.replace("%version_type%", "Alpha")
|
||||||
string = string.replace("%type_technical%", "a")
|
string = string.replace("%version_type_technical%", "a")
|
||||||
_: await logger.crashf("core", "Invalid version type " + str(version_type), true)
|
_: await logger.crashf("core", "Invalid version type " + str(version_type), true)
|
||||||
# Development mode
|
# Development mode
|
||||||
if is_devmode(): string = string.replace("%devmode%", "Enabled")
|
if is_devmode(): string = string.replace("%devmode%", "Enabled")
|
||||||
|
@ -261,9 +259,8 @@ func get_formatted_string(string: String) -> String:
|
||||||
else: string = string.replace("%custommodules%", "Disabled")
|
else: string = string.replace("%custommodules%", "Disabled")
|
||||||
return string
|
return string
|
||||||
|
|
||||||
# Return CORE's version in the semantic versioning scheme
|
|
||||||
## Returns CORE's versioning scheme into the semantic versioning scheme.[br]
|
## Returns CORE's versioning scheme into the semantic versioning scheme.[br]
|
||||||
## The first integer contains the release number, the second integer contains the release type ([code]0[/code] for alpha, [code]1[/code] for beta, [code]2[/code] for rc and [code]3[/code] for release and the last integer contains the typerelease number.
|
## The first integer contains the version number, the second integer contains the version type ([code]0[/code] for alpha, [code]1[/code] for beta, [code]2[/code] for rc and [code]3[/code] for release and the last integer contains the version type number.
|
||||||
func get_version_semantic() -> Array[int]:
|
func get_version_semantic() -> Array[int]:
|
||||||
var version_type_int: int
|
var version_type_int: int
|
||||||
match(version_type):
|
match(version_type):
|
||||||
|
@ -273,10 +270,8 @@ func get_version_semantic() -> Array[int]:
|
||||||
CoreTypes.VersionType.ALPHA: version_type_int = 0
|
CoreTypes.VersionType.ALPHA: version_type_int = 0
|
||||||
return [version_version, version_type_int, version_typerelease]
|
return [version_version, version_type_int, version_typerelease]
|
||||||
|
|
||||||
# Determines CORE's installation/base path
|
## Determines CORE's installation/base path.[br]
|
||||||
## Determines CORE's installation/base path[br]
|
## Danger: Do not call.
|
||||||
## [br]
|
|
||||||
## [b]Calling this function is likely to be safe, but shouldn't be done nonetheless![/b]
|
|
||||||
func determine_basepath() -> bool:
|
func determine_basepath() -> bool:
|
||||||
if FileAccess.file_exists("res://.corebasepath"):
|
if FileAccess.file_exists("res://.corebasepath"):
|
||||||
basepath = "res://"
|
basepath = "res://"
|
||||||
|
|
Loading…
Reference in a new issue