Skip to content

Commit 92cd37b

Browse files
authored
v6.3.0 (#528)
# Minor Release v6.3.0 Minor update to fix issues with script extension sorting, as well as potential issues with translations, configurations, and user profiles. ## Key PRs - #357 - #358 - #520 - #352 ## Change Log ### New Features - #352 - #358 ### Fixes - #357 - #520 - #522 - #523 - #524 ### Refactors - #521 - #526 ### Tests - #360 ### Miscellaneous - #525 - #527 - #529
2 parents 1bac6f6 + ccadca5 commit 92cd37b

39 files changed

+907
-58
lines changed
+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Inspired by https://github.com/bitbrain/beehave/blob/godot-4.x/.github/actions/godot-install/action.yml
2+
3+
name: install-godot-binary
4+
description: "Installs the Godot Runtime"
5+
6+
inputs:
7+
godot-version:
8+
description: "The Godot engine version"
9+
type: string
10+
required: true
11+
godot-status-version:
12+
description: "The Godot engine status version"
13+
type: string
14+
required: true
15+
godot-bin-name:
16+
type: string
17+
required: true
18+
godot-cache-path:
19+
type: string
20+
required: true
21+
22+
23+
runs:
24+
using: composite
25+
steps:
26+
27+
- name: "Set Cache Name"
28+
shell: bash
29+
run: |
30+
echo "CACHE_NAME=${{ runner.OS }}-Godot_v${{ inputs.godot-version }}-${{ inputs.godot-status-version }}" >> "$GITHUB_ENV"
31+
32+
- name: "Godot Cache Restore"
33+
uses: actions/cache/restore@v3
34+
id: godot-restore-cache
35+
with:
36+
path: ${{ inputs.godot-cache-path }}
37+
key: ${{ env.CACHE_NAME }}
38+
39+
- name: "Download and Install Godot ${{ inputs.godot-version }}"
40+
if: steps.godot-restore-cache.outputs.cache-hit != 'true'
41+
continue-on-error: false
42+
shell: bash
43+
run: |
44+
mkdir -p ${{ inputs.godot-cache-path }}
45+
chmod 770 ${{ inputs.godot-cache-path }}
46+
DIR="$HOME/.config/godot"
47+
if [ ! -d "$DIR" ]; then
48+
mkdir -p "$DIR"
49+
chmod 770 "$DIR"
50+
fi
51+
52+
DOWNLOAD_URL=https://github.com/godotengine/godot/releases/download/${{ inputs.godot-version }}-${{ inputs.godot-status-version }}
53+
GODOT_BIN=Godot_v${{ inputs.godot-version }}-${{ inputs.godot-status-version }}_${{ inputs.godot-bin-name }}
54+
55+
GODOT_PACKAGE=$GODOT_BIN.zip
56+
wget $DOWNLOAD_URL/$GODOT_PACKAGE -P ${{ inputs.godot-cache-path }}
57+
unzip ${{ inputs.godot-cache-path }}/$GODOT_PACKAGE -d ${{ inputs.godot-cache-path }}
58+
59+
mv ${{ inputs.godot-cache-path }}/$GODOT_BIN ${{ inputs.godot-cache-path }}/godot
60+
61+
chmod u+x ${{ inputs.godot-cache-path }}/godot
62+
echo "${{ inputs.godot-cache-path }}/godot"
63+
64+
- name: "Godot Cache Save"
65+
if: steps.godot-restore-cache.outputs.cache-hit != 'true'
66+
uses: actions/cache/save@v3
67+
with:
68+
path: ${{ inputs.godot-cache-path }}
69+
key: ${{ steps.godot-restore-cache.outputs.cache-primary-key }}

.github/actions/test/action.yml

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Inspired by https://github.com/utopia-rise/fmod-gdextension/blob/godot-3.x/demo/run_tests.sh
2+
3+
name: test
4+
description: "Runs the tests via GUT CLI"
5+
6+
inputs:
7+
gut-download-path:
8+
required: true
9+
default: ~/gut_download
10+
gut-addons-path:
11+
required: true
12+
default: ${{ github.workspace }}/test/addons/gut
13+
godot-test-project:
14+
required: true
15+
default: ${{ github.workspace }}/test
16+
17+
runs:
18+
using: composite
19+
20+
steps:
21+
22+
- name: "Set Cache Name"
23+
shell: bash
24+
run: |
25+
echo "CACHE_NAME_GUT=GUT_v7.4.1" >> "$GITHUB_ENV"
26+
27+
- name: "GUT Cache Restore"
28+
uses: actions/cache/restore@v3
29+
id: gut-restore-cache
30+
with:
31+
path: ${{ inputs.gut-download-path }}
32+
key: ${{ runner.os }}-${{ env.CACHE_NAME_GUT }}
33+
34+
- name: "Download GUT"
35+
if: steps.gut-restore-cache.outputs.cache-hit != 'true'
36+
continue-on-error: false
37+
shell: bash
38+
run: |
39+
mkdir -p ${{ inputs.gut-download-path }}
40+
chmod 770 ${{ inputs.gut-download-path }}
41+
42+
wget https://github.com/bitwes/Gut/archive/refs/tags/v7.4.1.zip -P ${{ inputs.gut-download-path }}
43+
unzip ${{ inputs.gut-download-path }}/v7.4.1.zip -d ${{ inputs.gut-download-path }}/unzip
44+
45+
- name: "GUT Cache Save"
46+
if: steps.gut-restore-cache.outputs.cache-hit != 'true'
47+
uses: actions/cache/save@v3
48+
with:
49+
path: ${{ inputs.gut-download-path }}
50+
key: ${{ steps.gut-restore-cache.outputs.cache-primary-key }}
51+
52+
- name: "Create addons Directory"
53+
if: ${{ !cancelled() }}
54+
shell: bash
55+
run: mkdir -p ${{ github.workspace }}/test/addons
56+
57+
- name: "⚔ Link GUT"
58+
if: ${{ !cancelled() }}
59+
shell: bash
60+
run: ln -s ${{ inputs.gut-download-path }}/unzip/Gut-7.4.1/addons/gut ${{ github.workspace }}/test/addons/gut
61+
62+
- name: "⚔ Link Mod Loader"
63+
if: ${{ !cancelled() }}
64+
shell: bash
65+
run: ln -s ${{ github.workspace }}/addons/mod_loader ${{ github.workspace }}/test/addons/mod_loader
66+
67+
- name: "⚔ Link JSON_Schema_Validator"
68+
if: ${{ !cancelled() }}
69+
shell: bash
70+
run: ln -s ${{ github.workspace }}/addons/JSON_Schema_Validator ${{ github.workspace }}/test/addons/JSON_Schema_Validator
71+
72+
- name: "Run Tests"
73+
if: ${{ runner.OS == 'Linux'}} && ${{ !cancelled() }}
74+
env:
75+
TEST_PROJECT: ${{ inputs.godot-test-project }}
76+
shell: bash
77+
run: |
78+
cd "${TEST_PROJECT}"
79+
chmod +x run_tests.sh
80+
./run_tests.sh "$HOME/godot-linux/godot"

.github/workflows/main.yml

+29-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,30 @@
1-
on: [pull_request]
1+
# Inspired by https://github.com/bitbrain/beehave/blob/godot-4.x/.github/workflows/beehave-ci.yml
2+
3+
name: Mod Loader CI
4+
5+
on:
6+
push:
7+
paths-ignore:
8+
- '**.jpg'
9+
- '**.png'
10+
- '**.svg'
11+
- '**.md'
12+
- '**plugin.cfg'
13+
pull_request:
14+
paths-ignore:
15+
- '**.jpg'
16+
- '**.png'
17+
- '**.svg'
18+
- '**.md'
19+
- '**plugin.cfg'
20+
21+
concurrency:
22+
group: ${{ github.workflow }}-${{ github.ref }}
23+
cancel-in-progress: true
24+
225
jobs:
3-
check_dependencies:
4-
runs-on: ubuntu-latest
5-
name: PR Dependency Check
6-
steps:
7-
- uses: gregsdennis/dependencies-action@main
8-
env:
9-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26+
tests:
27+
name: "Running GUT tests on Godot 3.5.3"
28+
uses: ./.github/workflows/tests.yml
29+
with:
30+
godot-version: '3.5.3'

.github/workflows/tests.yml

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Inspired by https://github.com/bitbrain/beehave/blob/godot-4.x/.github/workflows/unit-tests.yml
2+
3+
name: tests
4+
run-name: ${{ github.head_ref || github.ref_name }}-tests
5+
6+
on:
7+
workflow_call:
8+
inputs:
9+
os:
10+
required: false
11+
type: string
12+
default: 'ubuntu-22.04'
13+
godot-version:
14+
required: true
15+
type: string
16+
default: '3.5.3'
17+
18+
workflow_dispatch:
19+
inputs:
20+
os:
21+
required: false
22+
type: string
23+
default: 'ubuntu-22.04'
24+
godot-version:
25+
required: true
26+
type: string
27+
28+
concurrency:
29+
group: tests-${{ github.head_ref || github.ref_name }}-${{ inputs.godot-version }}
30+
cancel-in-progress: true
31+
32+
jobs:
33+
test:
34+
name: "Tests"
35+
runs-on: ${{ inputs.os }}
36+
timeout-minutes: 15
37+
38+
steps:
39+
- name: "📦 Checkout Mod Loader Repository"
40+
uses: actions/checkout@v4
41+
with:
42+
lfs: true
43+
submodules: 'recursive'
44+
45+
- name: "🤖 Install Godot ${{ inputs.godot-version }}"
46+
uses: ./.github/actions/godot-install
47+
with:
48+
godot-version: ${{ inputs.godot-version }}
49+
godot-status-version: 'stable'
50+
godot-bin-name: 'linux_headless.64'
51+
godot-cache-path: '~/godot-linux'
52+
53+
- name: "🧪 Run Tests"
54+
if: ${{ !cancelled() }}
55+
timeout-minutes: 4
56+
uses: ./.github/actions/test
57+
with:
58+
godot-test-project: ${{ github.workspace }}/test

README.md

+10-4
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ You can find detailed documentation, for game and mod developers, on the [Wiki](
2525
4. Use the [API Methods](https://wiki.godotmodding.com/#/api/mod_loader_api)
2626
*A list of all available API Methods.*
2727

28-
## Godot Version
29-
The current version of the Mod Loader is developed for Godot 3. The Godot 4 version is in progress on the [4.x branch](https://github.com/GodotModding/godot-mod-loader/tree/4.x) and can be used as long as no `class_name`s are in the project. Projects with `class_name`s are currently affected by an [engine bug](https://github.com/godotengine/godot/issues/83542). We are hopeful that this issue will be resolved in the near future. For more details and updates on the Godot 4 version, please follow this [issue](https://github.com/GodotModding/godot-mod-loader/issues/315) or join us on [our Discord](https://discord.godotmodding.com).
28+
## Godot Version
29+
The Mod Loader currently supports Godot 3.5 and later, as well as Godot 4.1 and later. Feel free to [open an issue](https://github.com/GodotModding/godot-mod-loader/issues/new) if you need support for a different version.
3030

31-
## Development
32-
The latest work-in-progress build can be found on the [development branch](https://github.com/GodotModding/godot-mod-loader/tree/development).
31+
## Development
32+
The latest work-in-progress build for Godot 3 is available on the [development branch](https://github.com/GodotModding/godot-mod-loader/tree/development). For Godot 4, visit the [4.x branch](https://github.com/GodotModding/godot-mod-loader/tree/4.x).
33+
34+
## Releases
35+
You can find the latest release versions and detailed installation instructions on the [Releases Page](https://github.com/GodotModding/godot-mod-loader/releases).
3336

3437
## Compatibility
3538
The Mod Loader supports the following platforms:
@@ -39,6 +42,9 @@ The Mod Loader supports the following platforms:
3942
- Android
4043
- iOS
4144

45+
## Keep in touche
46+
For more details and updates join us on [our Discord](https://discord.godotmodding.com).
47+
4248
## Games Made Moddable by This Project
4349
- [Brotato](https://store.steampowered.com/app/1942280/Brotato/) by
4450
[Blobfish Games](https://store.steampowered.com/developer/blobfishgames)

addons/mod_loader/api/log.gd

+17-5
Original file line numberDiff line numberDiff line change
@@ -385,15 +385,27 @@ static func _log(message: String, mod_name: String, log_type: String = "info", o
385385
_write_to_log_file(log_entry.get_entry())
386386

387387

388-
static func _is_mod_name_ignored(mod_name: String) -> bool:
388+
static func _is_mod_name_ignored(mod_log_name: String) -> bool:
389389
if not ModLoaderStore:
390390
return false
391391

392-
var ignored_mod_names := ModLoaderStore.ml_options.ignored_mod_names_in_log as Array
392+
var ignored_mod_log_names := ModLoaderStore.ml_options.ignored_mod_names_in_log as Array
393393

394-
if not ignored_mod_names.size() == 0:
395-
if mod_name in ignored_mod_names:
396-
return true
394+
# No ignored mod names
395+
if ignored_mod_log_names.size() == 0:
396+
return false
397+
398+
# Directly match a full mod log name. ex: "ModLoader:Deprecated"
399+
if mod_log_name in ignored_mod_log_names:
400+
return true
401+
402+
# Match a mod log name with a wildcard. ex: "ModLoader:*"
403+
for ignored_mod_name in ignored_mod_log_names:
404+
if ignored_mod_name.ends_with("*"):
405+
if mod_log_name.begins_with(ignored_mod_name.trim_suffix("*")):
406+
return true
407+
408+
# No match
397409
return false
398410

399411

addons/mod_loader/api/mod.gd

+7-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const LOG_NAME := "ModLoader:Mod"
2424
# Returns: void
2525
static func install_script_extension(child_script_path: String) -> void:
2626

27-
var mod_id: String = ModLoaderUtils.get_string_in_between(child_script_path, "res://mods-unpacked/", "/")
27+
var mod_id: String = _ModLoaderPath.get_mod_dir(child_script_path)
2828
var mod_data: ModData = get_mod_data(mod_id)
2929
if not ModLoaderStore.saved_extension_paths.has(mod_data.manifest.get_mod_id()):
3030
ModLoaderStore.saved_extension_paths[mod_data.manifest.get_mod_id()] = []
@@ -71,8 +71,12 @@ static func add_translation(resource_path: String) -> void:
7171
return
7272

7373
var translation_object: Translation = load(resource_path)
74-
TranslationServer.add_translation(translation_object)
75-
ModLoaderLog.info("Added Translation from Resource -> %s" % resource_path, LOG_NAME)
74+
if translation_object:
75+
TranslationServer.add_translation(translation_object)
76+
ModLoaderLog.info("Added Translation from Resource -> %s" % resource_path, LOG_NAME)
77+
else:
78+
ModLoaderLog.fatal("Failed to load translation at path: %s" % [resource_path], LOG_NAME)
79+
7680

7781

7882
# Appends a new node to a modified scene.

addons/mod_loader/api/profile.gd

+46
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,45 @@ static func create_profile(profile_name: String) -> bool:
9595
return is_save_success
9696

9797

98+
# Renames an existing user profile.
99+
#
100+
# Parameters:
101+
# - old_profile_name (String): The current name for the user profile (must be unique).
102+
# - new_profile_name (String): The new name for the user profile (must be unique).
103+
#
104+
# Returns: bool
105+
static func rename_profile(old_profile_name: String, new_profile_name: String) -> bool:
106+
# Verify that the old profile name is already in use
107+
if not ModLoaderStore.user_profiles.has(old_profile_name):
108+
ModLoaderLog.error("User profile with the name of \"%s\" does not exist." % old_profile_name, LOG_NAME)
109+
return false
110+
111+
# Verify that the new profile_name is not already in use
112+
if ModLoaderStore.user_profiles.has(new_profile_name):
113+
ModLoaderLog.error("User profile with the name of \"%s\" already exists." % new_profile_name, LOG_NAME)
114+
return false
115+
116+
# Rename user profile
117+
var profile_renamed := ModLoaderStore.user_profiles[old_profile_name].duplicate() as ModUserProfile
118+
profile_renamed.name = new_profile_name
119+
120+
# Remove old profile entry, replace it with new name entry in the ModLoaderStore
121+
ModLoaderStore.user_profiles.erase(old_profile_name)
122+
ModLoaderStore.user_profiles[new_profile_name] = profile_renamed
123+
124+
# Set it as the current profile if it was the current profile
125+
if ModLoaderStore.current_user_profile.name == old_profile_name:
126+
set_profile(profile_renamed)
127+
128+
# Store the new profile in the json file
129+
var is_save_success := _save()
130+
131+
if is_save_success:
132+
ModLoaderLog.debug("Renamed user profile from \"%s\" to \"%s\"" % [old_profile_name, new_profile_name], LOG_NAME)
133+
134+
return is_save_success
135+
136+
98137
# Sets the current user profile to the given user profile.
99138
#
100139
# Parameters:
@@ -187,6 +226,13 @@ static func get_all_as_array() -> Array:
187226
return user_profiles
188227

189228

229+
# Returns true if the Mod User Profiles are initialized.
230+
# On the first execution of the game, user profiles might not yet be created.
231+
# Use this method to check if everything is ready to interact with the ModLoaderUserProfile API.
232+
static func is_initialized() -> bool:
233+
return _ModLoaderFile.file_exists(FILE_PATH_USER_PROFILES)
234+
235+
190236
# Internal profile functions
191237
# =============================================================================
192238

0 commit comments

Comments
 (0)