From 661ee9603b500656421c4cf66d034c966c2892d5 Mon Sep 17 00:00:00 2001 From: kirito5572 Date: Wed, 10 Apr 2024 23:14:28 +0900 Subject: [PATCH 01/54] Create ko_kr.json Add Lang Support - Korean --- src/main/resources/assets/wi_zoom/lang/ko_kr.json | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/main/resources/assets/wi_zoom/lang/ko_kr.json diff --git a/src/main/resources/assets/wi_zoom/lang/ko_kr.json b/src/main/resources/assets/wi_zoom/lang/ko_kr.json new file mode 100644 index 0000000..8892a58 --- /dev/null +++ b/src/main/resources/assets/wi_zoom/lang/ko_kr.json @@ -0,0 +1,3 @@ +{ + "key.wi_zoom.zoom": "확대" +} \ No newline at end of file From edbccbf4fddef34d0eefdcab46e7d38cc9759700 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Tue, 25 Jun 2024 12:24:43 +0200 Subject: [PATCH 02/54] Run spotlessApply --- src/main/resources/assets/wi_zoom/lang/ko_kr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/wi_zoom/lang/ko_kr.json b/src/main/resources/assets/wi_zoom/lang/ko_kr.json index 8892a58..7d13f54 100644 --- a/src/main/resources/assets/wi_zoom/lang/ko_kr.json +++ b/src/main/resources/assets/wi_zoom/lang/ko_kr.json @@ -1,3 +1,3 @@ { "key.wi_zoom.zoom": "확대" -} \ No newline at end of file +} From e7885bbaacdc75cb79fb742285f4d4c1655c31af Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Wed, 30 Oct 2024 20:03:15 +0100 Subject: [PATCH 03/54] [Wurst-Bot] Update to 24w44a --- gradle.properties | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gradle.properties b/gradle.properties index cd4315a..feafc41 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,19 +5,19 @@ org.gradle.parallel=true # Fabric Properties # check these at https://fabricmc.net/develop/ and # https://modrinth.com/mod/fabric-api/versions -minecraft_version=1.21.3 -yarn_mappings=1.21.3+build.2 -loader_version=0.16.7 +minecraft_version=24w44a +yarn_mappings=24w44a+build.1 +loader_version=0.16.9 # Fabric API -fabric_version=0.106.1+1.21.3 +fabric_version=0.107.0+1.21.4 # Mod Properties -mod_version = 1.5-MC1.21.3 +mod_version = 1.5-MC24w44a maven_group = net.wurstclient.zoom archives_base_name = WI-Zoom # CurseForge -cf_game_version=1.21.3 +cf_game_version=1.21.2-Snapshot # Dependencies From 64229def2a5c21d7561a335c6a33d655ed04fdad Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Tue, 5 Nov 2024 10:57:58 +0100 Subject: [PATCH 04/54] Remove obsolete -dev jars These no longer do anything useful in modern Fabric versions. --- build.gradle | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/build.gradle b/build.gradle index 92b20c7..fc9d6f5 100644 --- a/build.gradle +++ b/build.gradle @@ -119,23 +119,15 @@ publishMods { } afterEvaluate { - tasks.publishMods.dependsOn moveDevLibs - tasks.publishCurseforge.dependsOn moveDevLibs - tasks.publishModrinth.dependsOn moveDevLibs -} - -task moveDevLibs(dependsOn: [remapJar, remapSourcesJar]) { - doLast { - def archivesName = project.base.archivesName.get() as String - ant.move(file:"${project.buildDir}/devlibs/${archivesName}-${version}-dev.jar", tofile:"${project.buildDir}/libs/${archivesName}-${version}-dev.jar") - ant.move(file:"${project.buildDir}/devlibs/${archivesName}-${version}-sources.jar", tofile:"${project.buildDir}/libs/${archivesName}-${version}-sources-dev.jar") - } + tasks.publishMods.dependsOn build + tasks.publishCurseforge.dependsOn build + tasks.publishModrinth.dependsOn build } import org.kohsuke.github.GHReleaseBuilder import org.kohsuke.github.GitHub -task github(dependsOn: moveDevLibs) { +task github(dependsOn: build) { onlyIf { ENV.GITHUB_TOKEN } @@ -144,7 +136,6 @@ task github(dependsOn: moveDevLibs) { def github = GitHub.connectUsingOAuth(ENV.GITHUB_TOKEN as String) def repository = github.getRepository("Wurst-Imperium-MCX/WI-Zoom") def ghVersion = "v" + version.substring(0, version.indexOf("-")) - def archivesName = project.base.archivesName.get() as String def ghRelease = repository.getReleaseByTagName(ghVersion as String) if(ghRelease == null) { @@ -154,7 +145,5 @@ task github(dependsOn: moveDevLibs) { ghRelease.uploadAsset(remapJar.archiveFile.get().getAsFile(), "application/java-archive") ghRelease.uploadAsset(remapSourcesJar.archiveFile.get().getAsFile(), "application/java-archive") - ghRelease.uploadAsset(new File("${project.buildDir}/libs/${archivesName}-${version}-dev.jar"), "application/java-archive") - ghRelease.uploadAsset(new File("${project.buildDir}/libs/${archivesName}-${version}-sources-dev.jar"), "application/java-archive") } } From 80a88e63332860c0a78a1c0417fb303c8a7084bb Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Thu, 7 Nov 2024 09:29:30 +0100 Subject: [PATCH 05/54] [Wurst-Bot] Update to 24w45a --- gradle.properties | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gradle.properties b/gradle.properties index feafc41..502f6c6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,19 +5,19 @@ org.gradle.parallel=true # Fabric Properties # check these at https://fabricmc.net/develop/ and # https://modrinth.com/mod/fabric-api/versions -minecraft_version=24w44a -yarn_mappings=24w44a+build.1 +minecraft_version=24w45a +yarn_mappings=24w45a+build.1 loader_version=0.16.9 # Fabric API -fabric_version=0.107.0+1.21.4 +fabric_version=0.107.2+1.21.4 # Mod Properties -mod_version = 1.5-MC24w44a +mod_version = 1.5-MC24w45a maven_group = net.wurstclient.zoom archives_base_name = WI-Zoom # CurseForge -cf_game_version=1.21.2-Snapshot +cf_game_version=1.21.4-snapshot # Dependencies From 6d11a0d0c42f3c17eedeb2a90046fd60fa8aae44 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Wed, 13 Nov 2024 21:04:30 +0100 Subject: [PATCH 06/54] [Wurst-Bot] Update to 24w46a --- gradle.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index 502f6c6..6f9b561 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,15 +5,15 @@ org.gradle.parallel=true # Fabric Properties # check these at https://fabricmc.net/develop/ and # https://modrinth.com/mod/fabric-api/versions -minecraft_version=24w45a -yarn_mappings=24w45a+build.1 +minecraft_version=24w46a +yarn_mappings=24w46a+build.4 loader_version=0.16.9 # Fabric API -fabric_version=0.107.2+1.21.4 +fabric_version=0.108.1+1.21.4 # Mod Properties -mod_version = 1.5-MC24w45a +mod_version = 1.5-MC24w46a maven_group = net.wurstclient.zoom archives_base_name = WI-Zoom From fdb1f58ccfc9e0bded35cbeca0b509524de85c32 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Wed, 20 Nov 2024 16:57:52 +0100 Subject: [PATCH 07/54] [Wurst-Bot] Update to 1.21.4-pre1 --- gradle.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index 6f9b561..fe2c640 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,15 +5,15 @@ org.gradle.parallel=true # Fabric Properties # check these at https://fabricmc.net/develop/ and # https://modrinth.com/mod/fabric-api/versions -minecraft_version=24w46a -yarn_mappings=24w46a+build.4 +minecraft_version=1.21.4-pre1 +yarn_mappings=1.21.4-pre1+build.1 loader_version=0.16.9 # Fabric API -fabric_version=0.108.1+1.21.4 +fabric_version=0.109.1+1.21.4 # Mod Properties -mod_version = 1.5-MC24w46a +mod_version = 1.5-MC1.21.4-pre1 maven_group = net.wurstclient.zoom archives_base_name = WI-Zoom From e7d646551ee05f54f819c0ee8278ced6133a7528 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Wed, 20 Nov 2024 17:58:26 +0100 Subject: [PATCH 08/54] Fix publishMods task --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6d2ef04..8e6ab2e 100644 --- a/build.gradle +++ b/build.gradle @@ -104,7 +104,7 @@ publishMods { file = remapJar.archiveFile def archivesName = base.archivesName.get() as String additionalFiles.from( - file("${project.buildDir}/libs/${archivesName}-${version}-sources.jar"), + file("${project.buildDir}/libs/${archivesName}-${project.version}-sources.jar"), ) type = getGhVersion().contains("pre") ? BETA : STABLE modLoaders.add("fabric") From 804ac10c6ea2903ffa873ec976502e2babb93587 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Fri, 22 Nov 2024 12:07:18 +0100 Subject: [PATCH 09/54] Update GHA workflows --- .github/workflows/gradle.yml | 4 ++++ .github/workflows/publish.yml | 21 ++++++++++++++++----- .github/workflows/stale.yml | 3 ++- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index c01d84e..2563435 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -1,4 +1,8 @@ name: Java CI with Gradle +run-name: | + ${{ github.event_name == 'pull_request' + && format('Test changes in PR #{0}: {1}', github.event.pull_request.number, github.event.pull_request.title) + || format('Test changes in {0}: {1}', github.ref_name, github.event.head_commit.message) }} on: push: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5aa3ade..79ac499 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,4 +1,9 @@ name: Publish Release +run-name: "Publish release from ${{ github.ref_name }} branch" + +permissions: + # Needed to push the tag. + contents: write on: workflow_dispatch: @@ -37,9 +42,13 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CURSEFORGE_API_KEY: ${{ secrets.CURSEFORGE_API_KEY }} MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} - steps: - - uses: actions/checkout@v4 + + - name: Checkout repository + uses: actions/checkout@v4 + with: + # Include all tags in case the new tag already exists. + fetch-tags: true - name: Set up Java 21 uses: actions/setup-java@v4 @@ -58,11 +67,11 @@ jobs: - name: Create and push tag run: | - MOD_VERSION=$(grep "mod_version" gradle.properties | cut -d'=' -f2 | tr -d ' ') + MOD_VERSION=$(grep "mod_version" gradle.properties | cut -d'=' -f2 | tr -d ' \r') git config --global user.name "Wurst-Bot" git config --global user.email "contact.wurstimperium@gmail.com" - git tag v$MOD_VERSION - git push origin v$MOD_VERSION + git tag "v$MOD_VERSION" + git push origin "v$MOD_VERSION" - name: Close milestone if: ${{ inputs.close_milestone }} @@ -85,3 +94,5 @@ jobs: - name: Publish to Modrinth if: ${{ inputs.publish_modrinth }} run: ./gradlew publishModrinth --stacktrace + +# TODO: Trigger website update diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index e0a1612..e7b27b7 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -13,7 +13,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/stale@v9 + - name: Run stale bot + uses: actions/stale@v9 with: stale-issue-message: | This issue has been open for a while with no recent activity. If this issue is still important to you, please add a comment within the next 7 days to keep it open. Otherwise, the issue will be automatically closed to free up time for other tasks. From 73883401255f6c392845e00b3f00bcc94711a3f5 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Sun, 24 Nov 2024 13:38:57 +0100 Subject: [PATCH 10/54] Add auto snapshot update workflow --- .github/workflows/auto_snapshot_update.yml | 98 ++++++++++++++++++++++ scripts/update_version_constants.py | 43 ++++++++++ 2 files changed, 141 insertions(+) create mode 100644 .github/workflows/auto_snapshot_update.yml create mode 100644 scripts/update_version_constants.py diff --git a/.github/workflows/auto_snapshot_update.yml b/.github/workflows/auto_snapshot_update.yml new file mode 100644 index 0000000..d547ba9 --- /dev/null +++ b/.github/workflows/auto_snapshot_update.yml @@ -0,0 +1,98 @@ +# Experimental workflow to automate updating to a new Minecraft snapshot. +name: Auto Snapshot Update + +on: + workflow_dispatch: + inputs: + mc_version: + description: "Minecraft version to update to" + required: true + yarn_mappings: + description: "Yarn mappings version" + required: true + fabric_loader: + description: "Fabric Loader version" + required: true + fapi_version: + description: "Fabric API version" + required: true + +permissions: + contents: write + +jobs: + update: + runs-on: ubuntu-latest + steps: + + - name: Checkout repository + uses: actions/checkout@v4 + with: + # Include all branches in case the new snapshot branch already exists. + fetch-depth: 0 + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Set up Java 21 + uses: actions/setup-java@v4 + with: + java-version: "21" + distribution: "microsoft" + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + build-scan-publish: true + build-scan-terms-of-use-url: "https://gradle.com/help/legal-terms-of-use" + build-scan-terms-of-use-agree: "yes" + + - name: Create and checkout new snapshot branch + run: | + BRANCH_NAME="${{ github.event.inputs.mc_version }}" + CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) + + if [ "$CURRENT_BRANCH" = "$BRANCH_NAME" ]; then + echo "Already on branch $BRANCH_NAME. Skipping branch creation." + elif git show-ref --quiet refs/heads/$BRANCH_NAME; then + echo "Branch $BRANCH_NAME already exists but is not currently checked out. Failing the workflow." + exit 1 + else + git checkout -b $BRANCH_NAME + echo "Created and checked out new branch: $BRANCH_NAME" + fi + shell: bash + + - name: Run migrateMappings task + run: | + ./gradlew migrateMappings --mappings ${{ github.event.inputs.yarn_mappings }} + shell: bash + + - name: Replace src/main/java with remapped files + run: | + rm -rf ./src/main/java + mv ./remappedSrc ./src/main/java + shell: bash + + - name: Update version constants + run: | + python scripts/update_version_constants.py "${{ github.event.inputs.mc_version }}" "${{ github.event.inputs.yarn_mappings }}" "${{ github.event.inputs.fabric_loader }}" "${{ github.event.inputs.fapi_version }}" + shell: bash + + # To fix any style issues that the migration scripts might cause + - name: Run spotlessApply task + run: ./gradlew spotlessApply + + - name: Commit and push changes + run: | + git config --global user.name "Wurst-Bot" + git config --global user.email "contact.wurstimperium@gmail.com" + git add . + git commit -m "[Wurst-Bot] Update to ${{ github.event.inputs.mc_version }}" + git push --set-upstream origin ${{ github.event.inputs.mc_version }} + shell: bash diff --git a/scripts/update_version_constants.py b/scripts/update_version_constants.py new file mode 100644 index 0000000..1bd7594 --- /dev/null +++ b/scripts/update_version_constants.py @@ -0,0 +1,43 @@ +import argparse + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("mc_version", help="Minecraft version") + parser.add_argument("yarn_mappings", help="Yarn mappings version") + parser.add_argument("fabric_loader", help="Fabric Loader version") + parser.add_argument("fapi_version", help="Fabric API version") + args = parser.parse_args() + + # Read gradle.properties + print("Updating gradle.properties...") + with open("gradle.properties", "r") as f: + lines = f.readlines() + + # Define replacements + replacements = { + "minecraft_version": lambda v: args.mc_version, + "yarn_mappings": lambda v: args.yarn_mappings, + "loader_version": lambda v: args.fabric_loader, + "fabric_version": lambda v: args.fapi_version, + "mod_version": lambda v: v[: v.index("MC") + 2] + args.mc_version, + } + + # Update lines + for i, line in enumerate(lines): + if line.startswith("#"): + continue + parts = line.split("=") + if len(parts) != 2: + continue + key = parts[0] + if key.strip() not in replacements: + continue + old_value = parts[1] + new_value = replacements[key.strip()](old_value) + print(f"{key}={old_value} -> {new_value}") + lines[i] = f"{key}={new_value}\n" + + # Save modified gradle.properties + with open("gradle.properties", "w") as f: + f.writelines(lines) + print("gradle.properties updated.") From 41826cd53dc6feedc9cf8297e2ca1ce26b2bd7e7 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Mon, 25 Nov 2024 17:29:21 +0100 Subject: [PATCH 11/54] Make snapshot update workflow also update cf_game_version --- .github/workflows/auto_snapshot_update.yml | 5 ++++- scripts/update_version_constants.py | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/auto_snapshot_update.yml b/.github/workflows/auto_snapshot_update.yml index d547ba9..e376122 100644 --- a/.github/workflows/auto_snapshot_update.yml +++ b/.github/workflows/auto_snapshot_update.yml @@ -16,6 +16,9 @@ on: fapi_version: description: "Fabric API version" required: true + cf_game_version: + description: "CurseForge GameVersion" + required: true permissions: contents: write @@ -81,7 +84,7 @@ jobs: - name: Update version constants run: | - python scripts/update_version_constants.py "${{ github.event.inputs.mc_version }}" "${{ github.event.inputs.yarn_mappings }}" "${{ github.event.inputs.fabric_loader }}" "${{ github.event.inputs.fapi_version }}" + python scripts/update_version_constants.py "${{ github.event.inputs.mc_version }}" "${{ github.event.inputs.yarn_mappings }}" "${{ github.event.inputs.fabric_loader }}" "${{ github.event.inputs.fapi_version }}" "${{ github.event.inputs.cf_game_version }}" shell: bash # To fix any style issues that the migration scripts might cause diff --git a/scripts/update_version_constants.py b/scripts/update_version_constants.py index 1bd7594..1a36c3a 100644 --- a/scripts/update_version_constants.py +++ b/scripts/update_version_constants.py @@ -6,6 +6,7 @@ parser.add_argument("yarn_mappings", help="Yarn mappings version") parser.add_argument("fabric_loader", help="Fabric Loader version") parser.add_argument("fapi_version", help="Fabric API version") + parser.add_argument("cf_game_version", help="CurseForge GameVersion") args = parser.parse_args() # Read gradle.properties @@ -20,6 +21,7 @@ "loader_version": lambda v: args.fabric_loader, "fabric_version": lambda v: args.fapi_version, "mod_version": lambda v: v[: v.index("MC") + 2] + args.mc_version, + "cf_game_version": lambda v: args.cf_game_version, } # Update lines From 8598298359f3ef68d3980fe076390b1068619f0d Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Mon, 25 Nov 2024 18:30:24 +0100 Subject: [PATCH 12/54] Fix CI not running after auto snapshot update --- .github/workflows/auto_snapshot_update.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/auto_snapshot_update.yml b/.github/workflows/auto_snapshot_update.yml index e376122..cb2692e 100644 --- a/.github/workflows/auto_snapshot_update.yml +++ b/.github/workflows/auto_snapshot_update.yml @@ -99,3 +99,12 @@ jobs: git commit -m "[Wurst-Bot] Update to ${{ github.event.inputs.mc_version }}" git push --set-upstream origin ${{ github.event.inputs.mc_version }} shell: bash + + # For some reason the commit above doesn't automatically trigger the CI + # workflow, so we need to explicitly start it here. + - name: Trigger CI on the new branch + env: + GH_TOKEN: ${{ github.token }} + run: | + gh workflow run gradle.yml --ref ${{ github.event.inputs.mc_version }} + shell: bash From c28b222c7f616f7ceb2d3256fb609ac47759d8c0 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Mon, 25 Nov 2024 19:09:06 +0100 Subject: [PATCH 13/54] Fix permission issue --- .github/workflows/auto_snapshot_update.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/auto_snapshot_update.yml b/.github/workflows/auto_snapshot_update.yml index cb2692e..96bb764 100644 --- a/.github/workflows/auto_snapshot_update.yml +++ b/.github/workflows/auto_snapshot_update.yml @@ -21,7 +21,10 @@ on: required: true permissions: + # To push changes to the new snapshot branch. contents: write + # To trigger the CI workflow. + actions: write jobs: update: From a452702afb65aad9426ea9112da48905a9e94ae5 Mon Sep 17 00:00:00 2001 From: Wurst-Bot Date: Mon, 25 Nov 2024 19:56:20 +0000 Subject: [PATCH 14/54] [Wurst-Bot] Update to 1.21.4-pre2 --- gradle.properties | 46 +++++++++++++++++++++++----------------------- gradlew | 0 2 files changed, 23 insertions(+), 23 deletions(-) mode change 100644 => 100755 gradlew diff --git a/gradle.properties b/gradle.properties index fe2c640..40d63c7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,23 +1,23 @@ -# Done to increase the memory available to gradle. -org.gradle.jvmargs=-Xmx1G -org.gradle.parallel=true - -# Fabric Properties -# check these at https://fabricmc.net/develop/ and -# https://modrinth.com/mod/fabric-api/versions -minecraft_version=1.21.4-pre1 -yarn_mappings=1.21.4-pre1+build.1 -loader_version=0.16.9 - -# Fabric API -fabric_version=0.109.1+1.21.4 - -# Mod Properties -mod_version = 1.5-MC1.21.4-pre1 -maven_group = net.wurstclient.zoom -archives_base_name = WI-Zoom - -# CurseForge -cf_game_version=1.21.4-snapshot - -# Dependencies +# Done to increase the memory available to gradle. +org.gradle.jvmargs=-Xmx1G +org.gradle.parallel=true + +# Fabric Properties +# check these at https://fabricmc.net/develop/ and +# https://modrinth.com/mod/fabric-api/versions +minecraft_version=1.21.4-pre2 +yarn_mappings=1.21.4-pre2+build.1 +loader_version=0.16.9 + +# Fabric API +fabric_version=0.110.0+1.21.4 + +# Mod Properties +mod_version = 1.5-MC1.21.4-pre2 +maven_group = net.wurstclient.zoom +archives_base_name = WI-Zoom + +# CurseForge +cf_game_version=1.21.4-snapshot + +# Dependencies diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 From 693d319b6661534b5da2a00d63fe37b2fe3daa9d Mon Sep 17 00:00:00 2001 From: Wurst-Bot Date: Tue, 26 Nov 2024 16:36:55 +0000 Subject: [PATCH 15/54] [Wurst-Bot] Update to 1.21.4-pre3 --- gradle.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index 40d63c7..3142daa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,19 +5,19 @@ org.gradle.parallel=true # Fabric Properties # check these at https://fabricmc.net/develop/ and # https://modrinth.com/mod/fabric-api/versions -minecraft_version=1.21.4-pre2 -yarn_mappings=1.21.4-pre2+build.1 +minecraft_version=1.21.4-pre3 +yarn_mappings=1.21.4-pre3+build.2 loader_version=0.16.9 # Fabric API fabric_version=0.110.0+1.21.4 # Mod Properties -mod_version = 1.5-MC1.21.4-pre2 +mod_version = 1.5-MC1.21.4-pre3 maven_group = net.wurstclient.zoom archives_base_name = WI-Zoom # CurseForge -cf_game_version=1.21.4-snapshot +cf_game_version=1.21.4-Snapshot # Dependencies From 5b224c5d341f75c9696754a086d0ac5bd7064fe4 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Thu, 28 Nov 2024 11:12:37 +0100 Subject: [PATCH 16/54] Update MPP to 0.8.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6d2ef04..9656571 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { plugins { id "fabric-loom" version "1.8-SNAPSHOT" - id "me.modmuss50.mod-publish-plugin" version "0.5.2" + id "me.modmuss50.mod-publish-plugin" version "0.8.1" id "com.diffplug.spotless" version "6.25.0" } From 1c732dc966309c66eed96fb0c58edf9b256596fb Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Thu, 28 Nov 2024 11:27:27 +0100 Subject: [PATCH 17/54] Set up Dependabot version updates for GHA and Gradle --- .github/dependabot.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..b9dbf06 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "gradle" + directory: "/" + schedule: + interval: "daily" + + - package-ecosystem: "github-actions" + # Directory should be `/` instead of `/.github/workflows` according to the docs. + directory: "/" + schedule: + interval: "daily" From 63aa7abbece2073edefbd7e92d76047afeae997d Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Thu, 28 Nov 2024 16:57:53 +0100 Subject: [PATCH 18/54] Remove overrides for msal4j and netty as they are no longer needed in 1.21.4 Closes #51 --- build.gradle | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/build.gradle b/build.gradle index 7c087b5..010b758 100644 --- a/build.gradle +++ b/build.gradle @@ -27,16 +27,6 @@ repositories { // for more information about repositories. } -// Override vulnerable dependencies until Minecraft updates to newer versions -configurations.all { - resolutionStrategy { - // v1.15.0, used by Minecraft 1.21.2 and 1.21.3, is vulnerable to CVE-2024-35255 - force "com.microsoft.azure:msal4j:1.17.2" - // v4.1.97.Final, used by Minecraft 1.21 - 1.21.3, is vulnerable to CVE-2024-47535 - force "io.netty:netty-common:4.1.115.Final" - } -} - dependencies { // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" From 5281944b410051f789e604fc6b58920e29ab63b6 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Thu, 28 Nov 2024 17:01:27 +0100 Subject: [PATCH 19/54] Update spotless gson version to 2.11 Matches the gson version that Minecraft uses as of 1.21.4. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 010b758..c68e80d 100644 --- a/build.gradle +++ b/build.gradle @@ -76,7 +76,7 @@ spotless { } json { target "src/**/*.json" - gson().indentWithSpaces(2).version("2.10.1") + gson().indentWithSpaces(2).version("2.11.0") } } From 805f4caba8995fd4ae169cddf6f21788b1f7f3b6 Mon Sep 17 00:00:00 2001 From: Wurst-Bot Date: Thu, 28 Nov 2024 16:18:45 +0000 Subject: [PATCH 20/54] [Wurst-Bot] Update to 1.21.4-rc1 --- gradle.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index 3142daa..58b3788 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,15 +5,15 @@ org.gradle.parallel=true # Fabric Properties # check these at https://fabricmc.net/develop/ and # https://modrinth.com/mod/fabric-api/versions -minecraft_version=1.21.4-pre3 -yarn_mappings=1.21.4-pre3+build.2 +minecraft_version=1.21.4-rc1 +yarn_mappings=1.21.4-rc1+build.1 loader_version=0.16.9 # Fabric API -fabric_version=0.110.0+1.21.4 +fabric_version=0.110.2+1.21.4 # Mod Properties -mod_version = 1.5-MC1.21.4-pre3 +mod_version = 1.5-MC1.21.4-rc1 maven_group = net.wurstclient.zoom archives_base_name = WI-Zoom From 113726caab782271e08ef0b1e746ddda76b50aa1 Mon Sep 17 00:00:00 2001 From: Wurst-Bot Date: Fri, 29 Nov 2024 15:13:53 +0000 Subject: [PATCH 21/54] [Wurst-Bot] Update to 1.21.4-rc2 --- gradle.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 58b3788..c9f909a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,15 +5,15 @@ org.gradle.parallel=true # Fabric Properties # check these at https://fabricmc.net/develop/ and # https://modrinth.com/mod/fabric-api/versions -minecraft_version=1.21.4-rc1 -yarn_mappings=1.21.4-rc1+build.1 +minecraft_version=1.21.4-rc2 +yarn_mappings=1.21.4-rc2+build.1 loader_version=0.16.9 # Fabric API fabric_version=0.110.2+1.21.4 # Mod Properties -mod_version = 1.5-MC1.21.4-rc1 +mod_version = 1.5-MC1.21.4-rc2 maven_group = net.wurstclient.zoom archives_base_name = WI-Zoom From ab7de8c1c7a0338a8cec50be86a0a66d6a6c1f83 Mon Sep 17 00:00:00 2001 From: Wurst-Bot Date: Fri, 29 Nov 2024 18:50:38 +0000 Subject: [PATCH 22/54] [Wurst-Bot] Update to 1.21.4-rc3 --- gradle.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index c9f909a..47112f2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,15 +5,15 @@ org.gradle.parallel=true # Fabric Properties # check these at https://fabricmc.net/develop/ and # https://modrinth.com/mod/fabric-api/versions -minecraft_version=1.21.4-rc2 -yarn_mappings=1.21.4-rc2+build.1 +minecraft_version=1.21.4-rc3 +yarn_mappings=1.21.4-rc3+build.1 loader_version=0.16.9 # Fabric API fabric_version=0.110.2+1.21.4 # Mod Properties -mod_version = 1.5-MC1.21.4-rc2 +mod_version = 1.5-MC1.21.4-rc3 maven_group = net.wurstclient.zoom archives_base_name = WI-Zoom From 26d57a00713fc479e5c874df1461a15809b7801d Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Tue, 3 Dec 2024 13:02:16 +0100 Subject: [PATCH 23/54] Update README.md --- README.md | 108 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 89 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index aac9921..e655294 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,28 @@ -![comparison of no zoom, 3x zoom, and 50x zoom](https://user-images.githubusercontent.com/10100202/67816432-973d2400-fab2-11e9-8699-e05eb5ba6551.jpg) - # WI Zoom (Wurst-Imperium Zoom) -The zoom from the [Wurst Client](https://www.wurstclient.net/) as a standalone mod. The WI Zoom Minecraft mod lets you zoom in and out with the mouse wheel, providing up to 50x magnification without the need for a spyglass. This mod is fully compatible with OptiFine and Sodium, but unlike OptiFine's zoom, WI Zoom lets the camera move in a logical way, without making it wobble around. WI Zoom supports all of the latest Minecraft versions, including snapshots. +WI Zoom is the zoom from the [Wurst Client](https://www.wurstclient.net/) as a standalone Minecraft mod, letting you zoom in and out with the mouse wheel and providing up to 50x magnification without the need for a spyglass. This mod is fully compatible with OptiFine and Sodium, but unlike OptiFine's zoom, WI Zoom lets the camera move in a logical way, without making it wobble around. WI Zoom supports all of the latest Minecraft versions, including snapshots. -![Requires Fabric API](https://user-images.githubusercontent.com/10100202/93722968-0aec9180-fb9b-11ea-9983-bc0fc51b47ab.png) +![comparison of no zoom, 3x zoom, and 50x zoom](https://user-images.githubusercontent.com/10100202/67816432-973d2400-fab2-11e9-8699-e05eb5ba6551.jpg) -## Downloads (for users) +## Downloads [![Download WI Zoom](https://user-images.githubusercontent.com/10100202/214881367-956f0bc9-4dbe-43cb-850a-04d73e00b344.png)](https://www.wimods.net/wi-zoom/download/?utm_source=GitHub&utm_medium=WI+Zoom&utm_campaign=README.md&utm_content=WI+Zoom+GitHub+repo+download+button) -## Setup (for developers) +## Installation -(This assumes that you are using Windows with [Eclipse](https://www.eclipse.org/downloads/) and [Java Development Kit 21](https://adoptium.net/?variant=openjdk21&jvmVariant=hotspot) already installed.) +> [!IMPORTANT] +> Always make sure that your modloader and all of your mods are made for the same Minecraft version. Your game will crash if you mix different versions. -1. Clone or download the repository. +### Installation using Fabric -2. Run this command in PowerShell: +1. Install [Fabric Loader](https://fabricmc.net/use/installer/). +2. Add [Fabric API](https://modrinth.com/mod/fabric-api) to your mods folder. +3. Add WI Zoom to your mods folder. - ```powershell - ./gradlew.bat genSources eclipse - ``` +### Installation using NeoForge -3. In Eclipse, go to `Import...` > `Existing Projects into Workspace` and select this project. +1. Install [NeoForge](https://neoforged.net/). +2. Add WI Zoom to your mods folder. ## Features @@ -33,30 +33,31 @@ The zoom from the [Wurst Client](https://www.wurstclient.net/) as a standalone m - Dynamic mouse sensitivity! (since v1.1) - Fully compatible with OptiFine / Sodium! -## How To Zoom +## How to zoom Hold down the V key to activate the zoom (this keybind can be changed). While zooming, you can use the mouse wheel to zoom in further. -## Changing The Zoom Keybind +## Changing the zoom keybind
How to change the keybind (click to expand) In the pause menu, click on "Options...". - screenshot of the Game Menu with the Options button highlighted + ![screenshot of the Game Menu with the Options button highlighted](https://user-images.githubusercontent.com/10100202/67876632-e0d45000-fb40-11e9-88a5-6d5d22cdb33a.png) In the Options menu, click on "Controls...". - screenshot of the Options menu with the Controls button highlighted + ![screenshot of the Options menu with the Controls button highlighted](https://user-images.githubusercontent.com/10100202/67876634-e0d45000-fb40-11e9-8e81-ef677755e1c3.png) In the Controls menu, scroll down to the "WI Zoom" section. If you don't have any other mods installed, you will find this section at the very bottom. - screenshot of the Controls menu with the WI Zoom keybind highlighted at the bottom + ![screenshot of the Controls menu with the WI Zoom keybind highlighted at the bottom](https://user-images.githubusercontent.com/10100202/67876636-e16ce680-fb40-11e9-8934-ad65580dc91a.png)
-## Supported Languages +## Supported languages + - Azerbaijani (Azerbaijan) (since v1.5) - Chinese (Simplified/Mainland) (since v1.4) - Chinese (Traditional/Taiwan) (since v1.4) @@ -72,3 +73,72 @@ While zooming, you can use the mouse wheel to zoom in further. - Russian (Russia) (since v1.3) - Turkish (Turkey) (since v1.5) - Ukrainian (Ukraine) (since v1.5) + +## Development Setup + +> [!IMPORTANT] +> Make sure you have [Java Development Kit 21](https://adoptium.net/?variant=openjdk21&jvmVariant=hotspot) installed. It won't work with other versions. + +### Development using Eclipse + +1. Clone the repository: + + ```pwsh + git clone https://github.com/Wurst-Imperium/WI-Zoom.git + cd WI-Zoom + ``` + +2. Generate the sources: + + In Fabric versions: + ```pwsh + ./gradlew genSources eclipse + ``` + + In NeoForge versions: + ```pwsh + ./gradlew eclipse + ``` + +3. In Eclipse, go to `Import...` > `Existing Projects into Workspace` and select this project. + +4. **Optional:** Right-click on the project and select `Properties` > `Java Code Style`. Then under `Clean Up`, `Code Templates`, `Formatter`, import the respective files in the `codestyle` folder. + +### Development using VSCode / Cursor + +> [!TIP] +> You'll probably want to install the [Extension Pack for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack) to make development easier. + +1. Clone the repository: + + ```pwsh + git clone https://github.com/Wurst-Imperium/WI-Zoom.git + cd WI-Zoom + ``` + +2. Generate the sources: + + In Fabric versions: + ```pwsh + ./gradlew genSources vscode + ``` + + In NeoForge versions: + ```pwsh + ./gradlew eclipse + ``` + (That's not a typo. NeoForge doesn't have `vscode`, but `eclipse` works fine.) + +3. Open the `WI-Zoom` folder in VSCode / Cursor. + +4. **Optional:** In the VSCode settings, set `java.format.settings.url` to `https://raw.githubusercontent.com/Wurst-Imperium/WI-Zoom/master/codestyle/formatter.xml` and `java.format.settings.profile` to `Wurst-Imperium`. + +### Development using IntelliJ IDEA + +I don't use or recommend IntelliJ, but the commands to run would be: + +```pwsh +git clone https://github.com/Wurst-Imperium/WI-Zoom.git +cd WI-Zoom +./gradlew genSources idea +``` From c65455fc52808dbfa3330b9cdc30296a51f5f1e3 Mon Sep 17 00:00:00 2001 From: Wurst-Bot Date: Tue, 3 Dec 2024 16:20:05 +0000 Subject: [PATCH 24/54] [Wurst-Bot] Update to 1.21.4 --- gradle.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index 47112f2..efcd7f7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,15 +5,15 @@ org.gradle.parallel=true # Fabric Properties # check these at https://fabricmc.net/develop/ and # https://modrinth.com/mod/fabric-api/versions -minecraft_version=1.21.4-rc3 -yarn_mappings=1.21.4-rc3+build.1 +minecraft_version=1.21.4 +yarn_mappings=1.21.4+build.1 loader_version=0.16.9 # Fabric API -fabric_version=0.110.2+1.21.4 +fabric_version=0.110.5+1.21.4 # Mod Properties -mod_version = 1.5-MC1.21.4-rc3 +mod_version = 1.5-MC1.21.4 maven_group = net.wurstclient.zoom archives_base_name = WI-Zoom From 0519bda4db99a110f5bb906a63f97f0228d4be6c Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Tue, 3 Dec 2024 17:30:38 +0100 Subject: [PATCH 25/54] Change Modrinth game version to 1.21.4-rc3 so the upload won't fail --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c68e80d..6db74f8 100644 --- a/build.gradle +++ b/build.gradle @@ -110,7 +110,7 @@ publishMods { modrinth { projectId = "o7DitHWP" accessToken = providers.environmentVariable("MODRINTH_TOKEN") - minecraftVersions.add("${project.minecraft_version}") + minecraftVersions.add("1.21.4-rc3") requires("fabric-api") changelog = "A changelog can be found at: [${changelogUrl}](${changelogUrl}?mc=${project.minecraft_version}&utm_source=Modrinth&utm_medium=WI+Zoom&utm_campaign=Changelog&utm_content=Modrinth+WI+Zoom+MC${project.minecraft_version})" } From 59fb741018e36651d9ddd27fba3f1ce23b74fbdd Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Thu, 5 Dec 2024 09:01:41 +0100 Subject: [PATCH 26/54] Revert "Change Modrinth game version to 1.21.4-rc3 so the upload won't fail" This reverts commit 0519bda4db99a110f5bb906a63f97f0228d4be6c. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6db74f8..c68e80d 100644 --- a/build.gradle +++ b/build.gradle @@ -110,7 +110,7 @@ publishMods { modrinth { projectId = "o7DitHWP" accessToken = providers.environmentVariable("MODRINTH_TOKEN") - minecraftVersions.add("1.21.4-rc3") + minecraftVersions.add("${project.minecraft_version}") requires("fabric-api") changelog = "A changelog can be found at: [${changelogUrl}](${changelogUrl}?mc=${project.minecraft_version}&utm_source=Modrinth&utm_medium=WI+Zoom&utm_campaign=Changelog&utm_content=Modrinth+WI+Zoom+MC${project.minecraft_version})" } From 00f92a8ec23e13e22e526e202a34fa45b16ee872 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Sun, 8 Dec 2024 19:45:29 +0100 Subject: [PATCH 27/54] Add option for publish workflow to trigger a website update --- .github/workflows/publish.yml | 29 ++++++++++++++++++++++++++++- build.gradle | 11 +++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 79ac499..c10d6e8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -33,6 +33,11 @@ on: required: true type: boolean default: true + update_website: + description: "Update wimods.net post (only works if there already is one and publish_curseforge is true)" + required: false + type: boolean + default: false jobs: publish: @@ -91,8 +96,30 @@ jobs: if: ${{ inputs.publish_curseforge }} run: ./gradlew publishCurseforge --stacktrace + - name: Get CurseForge file ID + id: cf_file_id + if: ${{ inputs.publish_curseforge }} + run: | + file_id=$(./gradlew getCurseforgeId | grep -o 'CURSEFORGE_FILE_ID=[0-9]*' | grep -o '[0-9]*') + echo "file_id=$file_id" >> "$GITHUB_OUTPUT" + echo "CurseForge file ID: `$file_id`" >> $GITHUB_STEP_SUMMARY + - name: Publish to Modrinth if: ${{ inputs.publish_modrinth }} run: ./gradlew publishModrinth --stacktrace -# TODO: Trigger website update + - name: Trigger website update + if: ${{ inputs.update_website && inputs.publish_curseforge }} + env: + GH_TOKEN: ${{ secrets.WIMODS_NET_PUBLISH_TOKEN }} + run: | + MOD_VERSION=$(grep "mod_version" gradle.properties | cut -d'=' -f2 | tr -d ' \r' | sed 's/-MC.*$//') + MC_VERSION=$(grep "minecraft_version" gradle.properties | cut -d'=' -f2 | tr -d ' \r') + FAPI_VERSION=$(grep "fabric_version" gradle.properties | cut -d'=' -f2 | tr -d ' \r') + gh workflow run add_mod_port.yml \ + -R Wurst-Imperium/wimods.net \ + -f mod="wi-zoom" \ + -f mod_version="$MOD_VERSION" \ + -f mc_version="$MC_VERSION" \ + -f fapi_version="$FAPI_VERSION" \ + -f file_id="${{ steps.cf_file_id.outputs.file_id }}" diff --git a/build.gradle b/build.gradle index c68e80d..4ed744f 100644 --- a/build.gradle +++ b/build.gradle @@ -116,10 +116,21 @@ publishMods { } } +import groovy.json.JsonSlurper + +tasks.register("getCurseforgeId") { + inputs.file publishCurseforge.result + doLast { + def result = new JsonSlurper().parseText(publishCurseforge.result.get().asFile.text) + println "CURSEFORGE_FILE_ID=${result.fileId}" + } +} + afterEvaluate { tasks.publishMods.dependsOn build tasks.publishCurseforge.dependsOn build tasks.publishModrinth.dependsOn build + tasks.getCurseforgeId.dependsOn publishCurseforge } import org.kohsuke.github.GHReleaseBuilder From 849fd5ac504500fe17942e873ecb1d6e0f02dff6 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Mon, 9 Dec 2024 21:55:18 +0100 Subject: [PATCH 28/54] Add modloader parameter to add_mod_port workflow --- .github/workflows/publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c10d6e8..95aadb9 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -119,6 +119,7 @@ jobs: gh workflow run add_mod_port.yml \ -R Wurst-Imperium/wimods.net \ -f mod="wi-zoom" \ + -f modloader="fabric" \ -f mod_version="$MOD_VERSION" \ -f mc_version="$MC_VERSION" \ -f fapi_version="$FAPI_VERSION" \ From 20ecdcbe49f310afd16ab2db5cb0f8e66959ecfa Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Tue, 17 Dec 2024 12:59:56 +0100 Subject: [PATCH 29/54] Update CI workflow --- .github/workflows/gradle.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 2563435..0dd86a6 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -1,13 +1,9 @@ name: Java CI with Gradle -run-name: | - ${{ github.event_name == 'pull_request' - && format('Test changes in PR #{0}: {1}', github.event.pull_request.number, github.event.pull_request.title) - || format('Test changes in {0}: {1}', github.ref_name, github.event.head_commit.message) }} on: push: - branches: - - "**" + branches-ignore: + - "dependabot/**" tags-ignore: - "**" paths: @@ -61,7 +57,7 @@ jobs: run: ./gradlew spotlessJsonCheck || (echo "::error::JSON validation failed! Run './gradlew spotlessApply' to fix style issues, or check the full error message for syntax errors." && exit 1) - name: Validate Java code style - run: ./gradlew spotlessCheck || (echo "::error::Java code style validation failed! To fix, run 'Clean Up' and then 'Format' in Eclipse, or './gradlew spotlessApply' in the terminal." && exit 1) + run: ./gradlew spotlessJavaCheck || (echo "::error::Java code style validation failed! To fix, run 'Clean Up' and then 'Format' in Eclipse, or './gradlew spotlessApply' in the terminal." && exit 1) - name: Run unit tests run: ./gradlew test --stacktrace --warning-mode=fail From b44f88b01e2a82e5ce798b31dd66c33d4f087531 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Tue, 17 Dec 2024 17:15:07 +0100 Subject: [PATCH 30/54] Update to Gradle 8.11.1 and Loom 1.9 --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 4ed744f..020fb18 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { } plugins { - id "fabric-loom" version "1.8-SNAPSHOT" + id "fabric-loom" version "1.9-SNAPSHOT" id "me.modmuss50.mod-publish-plugin" version "0.8.1" id "com.diffplug.spotless" version "6.25.0" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index df97d72..e2847c8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 2462a7e4d44f2ea95bcebbe7f4d9629ff6780fc1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Dec 2024 16:21:46 +0000 Subject: [PATCH 31/54] Bump me.modmuss50.mod-publish-plugin from 0.8.1 to 0.8.4 Bumps me.modmuss50.mod-publish-plugin from 0.8.1 to 0.8.4. --- updated-dependencies: - dependency-name: me.modmuss50.mod-publish-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 020fb18..3cdd685 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { plugins { id "fabric-loom" version "1.9-SNAPSHOT" - id "me.modmuss50.mod-publish-plugin" version "0.8.1" + id "me.modmuss50.mod-publish-plugin" version "0.8.4" id "com.diffplug.spotless" version "6.25.0" } From 9aadff3e15c217debaf4af34efb7895dede21ba4 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Thu, 2 Jan 2025 22:01:59 +0100 Subject: [PATCH 32/54] Make spotless manage the license header --- build.gradle | 7 +++++++ codestyle/license_header.txt | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 codestyle/license_header.txt diff --git a/build.gradle b/build.gradle index 020fb18..89dae63 100644 --- a/build.gradle +++ b/build.gradle @@ -66,6 +66,7 @@ jar { } } +import com.diffplug.spotless.generic.LicenseHeaderStep spotless { lineEndings("WINDOWS") java { @@ -74,6 +75,12 @@ spotless { trimTrailingWhitespace() eclipse().configFile(file("codestyle/formatter.xml")) } + format("license_header") { + target("src/*/java/**/*.java", "src/test/java/**/*.java") + def header_file = file("codestyle/license_header.txt") + def delimiter = LicenseHeaderStep.DEFAULT_JAVA_HEADER_DELIMITER + licenseHeaderFile(header_file, delimiter).updateYearWithLatest(true) + } json { target "src/**/*.json" gson().indentWithSpaces(2).version("2.11.0") diff --git a/codestyle/license_header.txt b/codestyle/license_header.txt new file mode 100644 index 0000000..9b2c5fc --- /dev/null +++ b/codestyle/license_header.txt @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2019-$YEAR Wurst-Imperium and contributors. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ From 291f957f7671ff872eeb90ef9d616c27185e96ff Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Thu, 2 Jan 2025 22:02:17 +0100 Subject: [PATCH 33/54] Run spotlessApply --- src/main/java/net/wurstclient/zoom/WiZoom.java | 2 +- src/main/java/net/wurstclient/zoom/WiZoomInitializer.java | 2 +- src/main/java/net/wurstclient/zoom/mixin/GameRendererMixin.java | 2 +- src/main/java/net/wurstclient/zoom/mixin/MouseMixin.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/wurstclient/zoom/WiZoom.java b/src/main/java/net/wurstclient/zoom/WiZoom.java index caeb821..46af7dc 100644 --- a/src/main/java/net/wurstclient/zoom/WiZoom.java +++ b/src/main/java/net/wurstclient/zoom/WiZoom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2024 Wurst-Imperium and contributors. + * Copyright (c) 2019-2025 Wurst-Imperium and contributors. * * This source code is subject to the terms of the GNU General Public * License, version 3. If a copy of the GPL was not distributed with this diff --git a/src/main/java/net/wurstclient/zoom/WiZoomInitializer.java b/src/main/java/net/wurstclient/zoom/WiZoomInitializer.java index 9b7de4f..c661786 100644 --- a/src/main/java/net/wurstclient/zoom/WiZoomInitializer.java +++ b/src/main/java/net/wurstclient/zoom/WiZoomInitializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2024 Wurst-Imperium and contributors. + * Copyright (c) 2019-2025 Wurst-Imperium and contributors. * * This source code is subject to the terms of the GNU General Public * License, version 3. If a copy of the GPL was not distributed with this diff --git a/src/main/java/net/wurstclient/zoom/mixin/GameRendererMixin.java b/src/main/java/net/wurstclient/zoom/mixin/GameRendererMixin.java index 0ad6e49..80c1255 100644 --- a/src/main/java/net/wurstclient/zoom/mixin/GameRendererMixin.java +++ b/src/main/java/net/wurstclient/zoom/mixin/GameRendererMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2024 Wurst-Imperium and contributors. + * Copyright (c) 2019-2025 Wurst-Imperium and contributors. * * This source code is subject to the terms of the GNU General Public * License, version 3. If a copy of the GPL was not distributed with this diff --git a/src/main/java/net/wurstclient/zoom/mixin/MouseMixin.java b/src/main/java/net/wurstclient/zoom/mixin/MouseMixin.java index ef412c7..b72d84e 100644 --- a/src/main/java/net/wurstclient/zoom/mixin/MouseMixin.java +++ b/src/main/java/net/wurstclient/zoom/mixin/MouseMixin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2024 Wurst-Imperium and contributors. + * Copyright (c) 2019-2025 Wurst-Imperium and contributors. * * This source code is subject to the terms of the GNU General Public * License, version 3. If a copy of the GPL was not distributed with this From dc02ea69c3dfcc5b5c791b3b64395f96b62bddc5 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Sat, 4 Jan 2025 14:58:55 +0100 Subject: [PATCH 34/54] Rename spotlessLicense_header task to spotlessLicenseHeader --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 89dae63..037c3d1 100644 --- a/build.gradle +++ b/build.gradle @@ -75,7 +75,7 @@ spotless { trimTrailingWhitespace() eclipse().configFile(file("codestyle/formatter.xml")) } - format("license_header") { + format("licenseHeader") { target("src/*/java/**/*.java", "src/test/java/**/*.java") def header_file = file("codestyle/license_header.txt") def delimiter = LicenseHeaderStep.DEFAULT_JAVA_HEADER_DELIMITER From 6277df551b429adf2622c829b0d6859a266cc079 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Sat, 4 Jan 2025 15:06:42 +0100 Subject: [PATCH 35/54] Add CI step for license header check --- .github/workflows/gradle.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 0dd86a6..b72f5a7 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -59,6 +59,9 @@ jobs: - name: Validate Java code style run: ./gradlew spotlessJavaCheck || (echo "::error::Java code style validation failed! To fix, run 'Clean Up' and then 'Format' in Eclipse, or './gradlew spotlessApply' in the terminal." && exit 1) + - name: Validate license headers + run: ./gradlew licenseHeaderCheck || (echo "::error::License headers are missing or malformed in some files! Run './gradlew spotlessApply' to fix this, or check the full error message for details." && exit 1) + - name: Run unit tests run: ./gradlew test --stacktrace --warning-mode=fail From 7c9b41e762891ed53b56471cdaa7012eec169fe7 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Sat, 4 Jan 2025 16:31:03 +0100 Subject: [PATCH 36/54] Fix license header task name --- .github/workflows/gradle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index b72f5a7..7af428c 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -60,7 +60,7 @@ jobs: run: ./gradlew spotlessJavaCheck || (echo "::error::Java code style validation failed! To fix, run 'Clean Up' and then 'Format' in Eclipse, or './gradlew spotlessApply' in the terminal." && exit 1) - name: Validate license headers - run: ./gradlew licenseHeaderCheck || (echo "::error::License headers are missing or malformed in some files! Run './gradlew spotlessApply' to fix this, or check the full error message for details." && exit 1) + run: ./gradlew spotlessLicenseHeaderCheck || (echo "::error::License headers are missing or malformed in some files! Run './gradlew spotlessApply' to fix this, or check the full error message for details." && exit 1) - name: Run unit tests run: ./gradlew test --stacktrace --warning-mode=fail From ee3af0b73a50f8edd38857394f682dd35e117cd1 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Sun, 5 Jan 2025 16:55:06 +0100 Subject: [PATCH 37/54] Add basic end-to-end test --- .github/workflows/gradle.yml | 52 +++ build.gradle | 49 +++ .../zoom/test/WiModsTestHelper.java | 399 ++++++++++++++++++ .../zoom/test/WiZoomTestClient.java | 128 ++++++ src/main/resources/fabric.mod.json | 4 + src/main/resources/wi-zoom.accesswidener | 4 + 6 files changed, 636 insertions(+) create mode 100644 src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java create mode 100644 src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java create mode 100644 src/main/resources/wi-zoom.accesswidener diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 7af428c..b76e252 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -98,3 +98,55 @@ jobs: echo "- [$filename]($url)" >> $GITHUB_STEP_SUMMARY done echo "" >> $GITHUB_STEP_SUMMARY + + - name: Run the mod and take screenshots + uses: modmuss50/xvfb-action@c56c7da0c8fc9a7cb5df2e50dd2a43a80b64c5cb + with: + run: ./gradlew runEndToEndTest --stacktrace --warning-mode=fail + + # Needed because the screenshot gallery won't be created on pull requests. + # Also useful if Imgur uploads fail. + - name: Upload Test Screenshots.zip artifact + uses: actions/upload-artifact@v4 + if: always() + with: + name: Test Screenshots + path: run/screenshots + + - name: Create test screenshot gallery + if: ${{ env.IMGUR_CLIENT_ID && (success() || failure()) }} + # Imgur uploads randomly fail sometimes, probably because of the low rate limit. + # TODO: Find a better place to upload the screenshots. + continue-on-error: true + run: | + echo "
" >> $GITHUB_STEP_SUMMARY + echo "📸 Test Screenshots" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + for img in run/screenshots/*.png; do + if [ -f "$img" ]; then + filename=$(basename "$img") + name_without_ext="${filename%.*}" + + # Upload to Imgur + response=$(curl -s -X POST \ + -H "Authorization: Client-ID $IMGUR_CLIENT_ID" \ + -F "image=@$img" \ + https://api.imgur.com/3/image) + + # Extract the URL from the response + url=$(echo $response | grep -o '"link":"[^"]*"' | cut -d'"' -f4) + + if [ ! -z "$url" ]; then + # Convert underscores to spaces and capitalize first letter of each word + title=$(echo "$name_without_ext" | tr '_' ' ' | awk '{for(i=1;i<=NF;i++)sub(/./,toupper(substr($i,1,1)),$i)}1') + echo "### $title" >> $GITHUB_STEP_SUMMARY + echo "![${name_without_ext}]($url)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + else + echo "Failed to upload $filename" >> $GITHUB_STEP_SUMMARY + echo "Imgur upload response for $filename: $response" + fi + fi + done + echo "
" >> $GITHUB_STEP_SUMMARY diff --git a/build.gradle b/build.gradle index 037c3d1..15477b4 100644 --- a/build.gradle +++ b/build.gradle @@ -37,6 +37,55 @@ dependencies { modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" } +loom { + accessWidenerPath = file("src/main/resources/wi-zoom.accesswidener") +} + +configurations { + productionRuntime { + extendsFrom configurations.minecraftLibraries + extendsFrom configurations.loaderLibraries + extendsFrom configurations.minecraftRuntimeLibraries + } +} + +dependencies { + productionRuntime "net.fabricmc:fabric-loader:${project.loader_version}" + productionRuntime "net.fabricmc:intermediary:${project.minecraft_version}" +} + +import net.fabricmc.loom.util.Platform +tasks.register('runEndToEndTest', JavaExec) { + dependsOn remapJar, downloadAssets + classpath.from configurations.productionRuntime + mainClass = "net.fabricmc.loader.impl.launch.knot.KnotClient" + workingDir = file("run") + + doFirst { + classpath.from loom.minecraftProvider.minecraftClientJar + workingDir.mkdirs() + + args( + "--assetIndex", loom.minecraftProvider.versionInfo.assetIndex().fabricId(loom.minecraftProvider.minecraftVersion()), + "--assetsDir", new File(loom.files.userCache, "assets").absolutePath, + "--gameDir", workingDir.absolutePath + ) + + if (Platform.CURRENT.operatingSystem.isMacOS()) { + jvmArgs("-XstartOnFirstThread") + } + + jvmArgs( + "-Dfabric.addMods=${configurations.modImplementation.find { it.name.contains('fabric-api') }.absolutePath}${File.pathSeparator}${remapJar.archiveFile.get().asFile.absolutePath}", + "-Dwi_zoom.e2eTest", + "-Dfabric-tag-conventions-v2.missingTagTranslationWarning=fail", + "-Dfabric-tag-conventions-v1.legacyTagWarning=fail", + "-Dmixin.debug.verify=true", + "-Dmixin.debug.countInjections=true" + ) + } +} + processResources { inputs.property "version", project.version diff --git a/src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java b/src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java new file mode 100644 index 0000000..0e1fb9a --- /dev/null +++ b/src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2019-2025 Wurst-Imperium and contributors. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ +package net.wurstclient.zoom.test; + +import java.io.File; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; + +import com.mojang.brigadier.ParseResults; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.Drawable; +import net.minecraft.client.gui.screen.GameMenuScreen; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.TitleScreen; +import net.minecraft.client.gui.screen.ingame.InventoryScreen; +import net.minecraft.client.gui.screen.world.LevelLoadingScreen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.ClickableWidget; +import net.minecraft.client.gui.widget.CyclingButtonWidget; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.client.option.Perspective; +import net.minecraft.client.resource.language.I18n; +import net.minecraft.client.tutorial.TutorialStep; +import net.minecraft.client.util.ScreenshotRecorder; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +public enum WiModsTestHelper +{ + ; + + private static final AtomicInteger screenshotCounter = new AtomicInteger(0); + + /** + * Runs the given consumer on Minecraft's main thread and waits for it to + * complete. + */ + public static void submitAndWait(Consumer consumer) + { + MinecraftClient mc = MinecraftClient.getInstance(); + mc.submit(() -> consumer.accept(mc)).join(); + } + + /** + * Runs the given function on Minecraft's main thread, waits for it to + * complete, and returns the result. + */ + public static T submitAndGet(Function function) + { + MinecraftClient mc = MinecraftClient.getInstance(); + return mc.submit(() -> function.apply(mc)).join(); + } + + /** + * Waits for the given duration. + */ + public static void wait(Duration duration) + { + try + { + Thread.sleep(duration.toMillis()); + + }catch(InterruptedException e) + { + throw new RuntimeException(e); + } + } + + /** + * Waits until the given condition is true, or fails if the timeout is + * reached. + */ + public static void waitUntil(String event, + Predicate condition, Duration maxDuration) + { + LocalDateTime startTime = LocalDateTime.now(); + LocalDateTime timeout = startTime.plus(maxDuration); + System.out.println("Waiting until " + event); + + while(true) + { + if(submitAndGet(condition::test)) + { + double seconds = + Duration.between(startTime, LocalDateTime.now()).toMillis() + / 1000.0; + System.out.println( + "Waiting until " + event + " took " + seconds + "s"); + break; + } + + if(startTime.isAfter(timeout)) + throw new RuntimeException( + "Waiting until " + event + " took too long"); + + wait(Duration.ofMillis(50)); + } + } + + /** + * Waits until the given condition is true, or fails after 10 seconds. + */ + public static void waitUntil(String event, + Predicate condition) + { + waitUntil(event, condition, Duration.ofSeconds(10)); + } + + /** + * Waits until the given screen is open, or fails after 10 seconds. + */ + public static void waitForScreen(Class screenClass) + { + waitUntil("screen " + screenClass.getName() + " is open", + mc -> screenClass.isInstance(mc.currentScreen)); + } + + /** + * Waits for the fading animation of the title screen to finish, or fails + * after 10 seconds. + */ + public static void waitForTitleScreenFade() + { + waitUntil("title screen fade is complete", mc -> { + if(!(mc.currentScreen instanceof TitleScreen titleScreen)) + return false; + + return !titleScreen.doBackgroundFade; + }); + } + + /** + * Waits until the red overlay with the Mojang logo and progress bar goes + * away, or fails after 5 minutes. + */ + public static void waitForResourceLoading() + { + waitUntil("loading is complete", mc -> mc.getOverlay() == null, + Duration.ofMinutes(5)); + } + + public static void waitForWorldLoad() + { + waitUntil("world is loaded", + mc -> mc.world != null + && !(mc.currentScreen instanceof LevelLoadingScreen), + Duration.ofMinutes(30)); + } + + public static void waitForWorldTicks(int ticks) + { + long startTicks = submitAndGet(mc -> mc.world.getTime()); + waitUntil(ticks + " world ticks have passed", + mc -> mc.world.getTime() >= startTicks + ticks, + Duration.ofMillis(ticks * 100).plusMinutes(5)); + } + + /** + * Waits for 50ms and then takes a screenshot with the given name. + */ + public static void takeScreenshot(String name) + { + takeScreenshot(name, Duration.ofMillis(50)); + } + + /** + * Waits for the given delay and then takes a screenshot with the given + * name. + */ + public static void takeScreenshot(String name, Duration delay) + { + wait(delay); + + String count = + String.format("%02d", screenshotCounter.incrementAndGet()); + String filename = count + "_" + name + ".png"; + File gameDir = FabricLoader.getInstance().getGameDir().toFile(); + + submitAndWait(mc -> ScreenshotRecorder.saveScreenshot(gameDir, filename, + mc.getFramebuffer(), message -> {})); + } + + /** + * Returns the first button on the current screen that has the given + * translation key, or fails if not found. + * + *

+ * For non-translated buttons, the translationKey parameter should be the + * raw button text instead. + */ + public static ButtonWidget findButton(MinecraftClient mc, + String translationKey) + { + String message = I18n.translate(translationKey); + + for(Drawable drawable : mc.currentScreen.drawables) + if(drawable instanceof ButtonWidget button + && button.getMessage().getString().equals(message)) + return button; + + throw new RuntimeException(message + " button could not be found"); + } + + /** + * Looks for the given button at the given coordinates and fails if it is + * not there. + */ + public static void checkButtonPosition(ButtonWidget button, int expectedX, + int expectedY) + { + String buttonName = button.getMessage().getString(); + + if(button.getX() != expectedX) + throw new RuntimeException(buttonName + + " button is at the wrong X coordinate. Expected X: " + + expectedX + ", actual X: " + button.getX()); + + if(button.getY() != expectedY) + throw new RuntimeException(buttonName + + " button is at the wrong Y coordinate. Expected Y: " + + expectedY + ", actual Y: " + button.getY()); + } + + /** + * Clicks the button with the given translation key, or fails after 10 + * seconds. + * + *

+ * For non-translated buttons, the translationKey parameter should be the + * raw button text instead. + */ + public static void clickButton(String translationKey) + { + String buttonText = I18n.translate(translationKey); + + waitUntil("button saying " + buttonText + " is visible", mc -> { + Screen screen = mc.currentScreen; + if(screen == null) + return false; + + for(Drawable drawable : screen.drawables) + { + if(!(drawable instanceof ClickableWidget widget)) + continue; + + if(widget instanceof ButtonWidget button + && buttonText.equals(button.getMessage().getString())) + { + button.onPress(); + return true; + } + + if(widget instanceof CyclingButtonWidget button + && buttonText.equals(button.optionText.getString())) + { + button.onPress(); + return true; + } + } + + return false; + }); + } + + /** + * Types the given text into the nth text field on the current screen, or + * fails after 10 seconds. + */ + public static void setTextFieldText(int index, String text) + { + waitUntil("text field #" + index + " is visible", mc -> { + Screen screen = mc.currentScreen; + if(screen == null) + return false; + + int i = 0; + for(Drawable drawable : screen.drawables) + { + if(!(drawable instanceof TextFieldWidget textField)) + continue; + + if(i == index) + { + textField.setText(text); + return true; + } + + i++; + } + + return false; + }); + } + + public static void closeScreen() + { + submitAndWait(mc -> mc.setScreen(null)); + } + + public static void openGameMenu() + { + submitAndWait(mc -> mc.setScreen(new GameMenuScreen(true))); + } + + public static void openInventory() + { + submitAndWait(mc -> mc.setScreen(new InventoryScreen(mc.player))); + } + + public static void toggleDebugHud() + { + submitAndWait(mc -> mc.inGameHud.getDebugHud().toggleDebugHud()); + } + + public static void setPerspective(Perspective perspective) + { + submitAndWait(mc -> mc.options.setPerspective(perspective)); + } + + public static void dismissTutorialToasts() + { + submitAndWait(mc -> mc.getTutorialManager().setStep(TutorialStep.NONE)); + } + + public static void clearChat() + { + submitAndWait(mc -> mc.inGameHud.getChatHud().clear(true)); + } + + /** + * Runs the given chat command and waits one tick for the action to + * complete. + * + *

+ * Do not put a / at the start of the command. + */ + public static void runChatCommand(String command) + { + System.out.println("Running command: /" + command); + submitAndWait(mc -> { + ClientPlayNetworkHandler netHandler = mc.getNetworkHandler(); + + // Validate command using client-side command dispatcher + ParseResults results = netHandler.getCommandDispatcher() + .parse(command, netHandler.getCommandSource()); + + // Command is invalid, fail the test + if(!results.getExceptions().isEmpty()) + { + StringBuilder errors = + new StringBuilder("Invalid command: " + command); + for(CommandSyntaxException e : results.getExceptions().values()) + errors.append("\n").append(e.getMessage()); + + throw new RuntimeException(errors.toString()); + } + + // Command is valid, send it + netHandler.sendChatCommand(command); + }); + waitForWorldTicks(1); + } + + public static void assertOneItemInSlot(int slot, Item item) + { + submitAndWait(mc -> { + ItemStack stack = mc.player.getInventory().getStack(slot); + if(!stack.isOf(item) || stack.getCount() != 1) + throw new RuntimeException( + "Expected 1 " + item.getName().getString() + " at slot " + + slot + ", found " + stack.getCount() + " " + + stack.getItem().getName().getString() + " instead"); + }); + } + + public static void assertNoItemInSlot(int slot) + { + submitAndWait(mc -> { + ItemStack stack = mc.player.getInventory().getStack(slot); + if(!stack.isEmpty()) + throw new RuntimeException("Expected no item in slot " + slot + + ", found " + stack.getCount() + " " + + stack.getItem().getName().getString() + " instead"); + }); + } +} diff --git a/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java b/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java new file mode 100644 index 0000000..f961def --- /dev/null +++ b/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2019-2025 Wurst-Imperium and contributors. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ +package net.wurstclient.zoom.test; + +import static net.wurstclient.zoom.test.WiModsTestHelper.*; + +import java.time.Duration; + +import org.spongepowered.asm.mixin.MixinEnvironment; + +import net.fabricmc.api.ClientModInitializer; +import net.minecraft.SharedConstants; +import net.minecraft.client.gui.screen.AccessibilityOnboardingScreen; +import net.minecraft.client.gui.screen.TitleScreen; +import net.minecraft.client.gui.screen.world.CreateWorldScreen; +import net.minecraft.client.gui.screen.world.SelectWorldScreen; + +public final class WiZoomTestClient implements ClientModInitializer +{ + @Override + public void onInitializeClient() + { + if(System.getProperty("wi_zoom.e2eTest") == null) + return; + + Thread.ofVirtual().name("WI Zoom End-to-End Test") + .uncaughtExceptionHandler((t, e) -> { + e.printStackTrace(); + System.exit(1); + }).start(this::runTests); + } + + private void runTests() + { + System.out.println("Starting WI Zoom End-to-End Test"); + waitForResourceLoading(); + + if(submitAndGet(mc -> mc.options.onboardAccessibility)) + { + System.out.println("Onboarding is enabled. Waiting for it"); + waitForScreen(AccessibilityOnboardingScreen.class); + System.out.println("Reached onboarding screen"); + clickButton("gui.continue"); + } + + waitForScreen(TitleScreen.class); + waitForTitleScreenFade(); + System.out.println("Reached title screen"); + takeScreenshot("title_screen", Duration.ZERO); + + System.out.println("Clicking singleplayer button"); + clickButton("menu.singleplayer"); + + if(submitAndGet(mc -> !mc.getLevelStorage().getLevelList().isEmpty())) + { + System.out.println("World list is not empty. Waiting for it"); + waitForScreen(SelectWorldScreen.class); + System.out.println("Reached select world screen"); + takeScreenshot("select_world_screen"); + clickButton("selectWorld.create"); + } + + waitForScreen(CreateWorldScreen.class); + System.out.println("Reached create world screen"); + + // Set MC version as world name + setTextFieldText(0, + "E2E Test " + SharedConstants.getGameVersion().getName()); + // Select creative mode + clickButton("selectWorld.gameMode"); + clickButton("selectWorld.gameMode"); + takeScreenshot("create_world_screen"); + + System.out.println("Creating test world"); + clickButton("selectWorld.create"); + + waitForWorldLoad(); + dismissTutorialToasts(); + waitForWorldTicks(200); + runChatCommand("seed"); + System.out.println("Reached singleplayer world"); + takeScreenshot("in_game", Duration.ZERO); + clearChat(); + + System.out.println("Opening debug menu"); + toggleDebugHud(); + takeScreenshot("debug_menu"); + + System.out.println("Closing debug menu"); + toggleDebugHud(); + + System.out.println("Checking for broken mixins"); + MixinEnvironment.getCurrentEnvironment().audit(); + + System.out.println("Opening inventory"); + openInventory(); + takeScreenshot("inventory"); + + System.out.println("Closing inventory"); + closeScreen(); + + // Build a test platform and clear out the space above it + runChatCommand("fill ~-5 ~-1 ~-5 ~5 ~-1 ~5 stone"); + runChatCommand("fill ~-5 ~ ~-5 ~5 ~30 ~5 air"); + + // Clear inventory and chat before running tests + runChatCommand("clear"); + clearChat(); + + // TODO: Add WI Zoom-specific test code here + + System.out.println("Opening game menu"); + openGameMenu(); + takeScreenshot("game_menu"); + + System.out.println("Returning to title screen"); + clickButton("menu.returnToMenu"); + waitForScreen(TitleScreen.class); + + System.out.println("Stopping the game"); + clickButton("menu.quit"); + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index a6560b1..63fa649 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -20,11 +20,15 @@ "entrypoints": { "main": [ "net.wurstclient.zoom.WiZoomInitializer" + ], + "client": [ + "net.wurstclient.zoom.test.WiZoomTestClient" ] }, "mixins": [ "wi-zoom.mixins.json" ], + "accessWidener": "wi-zoom.accesswidener", "depends": { "fabricloader": ">=0.16.2", "fabric-api": ">=0.102.2", diff --git a/src/main/resources/wi-zoom.accesswidener b/src/main/resources/wi-zoom.accesswidener new file mode 100644 index 0000000..a9e23b8 --- /dev/null +++ b/src/main/resources/wi-zoom.accesswidener @@ -0,0 +1,4 @@ +accessWidener v1 named +accessible field net/minecraft/client/gui/screen/Screen drawables Ljava/util/List; +accessible field net/minecraft/client/gui/screen/TitleScreen doBackgroundFade Z +accessible field net/minecraft/client/gui/widget/CyclingButtonWidget optionText Lnet/minecraft/text/Text; From 0fbb27de885562048595263b8f73a8e88fa46303 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Sun, 5 Jan 2025 18:24:34 +0100 Subject: [PATCH 38/54] Add test for zoom functionality --- .../zoom/test/WiZoomTestClient.java | 51 +++++++++++++++++-- src/main/resources/wi-zoom.accesswidener | 1 + 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java b/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java index f961def..d5bdd54 100644 --- a/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java +++ b/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java @@ -11,6 +11,7 @@ import java.time.Duration; +import org.lwjgl.glfw.GLFW; import org.spongepowered.asm.mixin.MixinEnvironment; import net.fabricmc.api.ClientModInitializer; @@ -19,6 +20,7 @@ import net.minecraft.client.gui.screen.TitleScreen; import net.minecraft.client.gui.screen.world.CreateWorldScreen; import net.minecraft.client.gui.screen.world.SelectWorldScreen; +import net.minecraft.util.math.MathHelper; public final class WiZoomTestClient implements ClientModInitializer { @@ -105,14 +107,14 @@ private void runTests() closeScreen(); // Build a test platform and clear out the space above it - runChatCommand("fill ~-5 ~-1 ~-5 ~5 ~-1 ~5 stone"); - runChatCommand("fill ~-5 ~ ~-5 ~5 ~30 ~5 air"); + runChatCommand("fill ~-1 ~-1 ~-1 ~1 ~-1 ~15 stone"); + runChatCommand("fill ~-1 ~ ~-1 ~1 ~30 ~15 air"); // Clear inventory and chat before running tests runChatCommand("clear"); clearChat(); - // TODO: Add WI Zoom-specific test code here + testZoomInWorld(); System.out.println("Opening game menu"); openGameMenu(); @@ -125,4 +127,47 @@ private void runTests() System.out.println("Stopping the game"); clickButton("menu.quit"); } + + private void testZoomInWorld() + { + // Spawn a chicken in front of the player + runChatCommand( + "summon minecraft:chicken ~ ~0.85 ~15 {NoAI:1,NoGravity:1,Rotation:[180f,0f]}"); + waitForWorldTicks(5); + takeScreenshot("chicken_no_zoom"); + + // Press V to enable zoom + setKeyPressState(GLFW.GLFW_KEY_V, true); + waitForWorldTicks(1); + takeScreenshot("chicken_3x_zoom"); + + // Scroll up to increase zoom + int scrollsNeededFor50x = + MathHelper.ceil(Math.log(50 / 3) / Math.log(1.1)); + for(int i = 0; i < scrollsNeededFor50x; i++) + scrollUp(); + waitForWorldTicks(1); + takeScreenshot("chicken_50x_zoom"); + + // Confirm selected slot is still zero + if(submitAndGet(mc -> mc.player.getInventory().selectedSlot != 0)) + throw new RuntimeException( + "Scrolling up while zooming changed the selected slot"); + + // Release V to disable zoom + setKeyPressState(GLFW.GLFW_KEY_V, false); + waitForWorldTicks(1); + } + + private void setKeyPressState(int key, boolean pressed) + { + submitAndWait(mc -> mc.keyboard.onKey(mc.getWindow().getHandle(), key, + 0, pressed ? 1 : 0, 0)); + } + + private void scrollUp() + { + submitAndWait( + mc -> mc.mouse.onMouseScroll(mc.getWindow().getHandle(), 0, 1)); + } } diff --git a/src/main/resources/wi-zoom.accesswidener b/src/main/resources/wi-zoom.accesswidener index a9e23b8..70c3a70 100644 --- a/src/main/resources/wi-zoom.accesswidener +++ b/src/main/resources/wi-zoom.accesswidener @@ -2,3 +2,4 @@ accessWidener v1 named accessible field net/minecraft/client/gui/screen/Screen drawables Ljava/util/List; accessible field net/minecraft/client/gui/screen/TitleScreen doBackgroundFade Z accessible field net/minecraft/client/gui/widget/CyclingButtonWidget optionText Lnet/minecraft/text/Text; +accessible method net/minecraft/client/Mouse onMouseScroll (JDD)V From 1fa156b6bd8edb916472f4d5f17df232c23596f0 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Mon, 6 Jan 2025 14:51:47 +0100 Subject: [PATCH 39/54] Update WiModsTestHelper --- .../zoom/test/WiModsTestHelper.java | 26 ++++++++++++++++++- .../zoom/test/WiZoomTestClient.java | 14 +--------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java b/src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java index 0e1fb9a..00961b5 100644 --- a/src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java +++ b/src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java @@ -19,6 +19,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.block.Block; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.Drawable; import net.minecraft.client.gui.screen.GameMenuScreen; @@ -37,6 +38,7 @@ import net.minecraft.client.util.ScreenshotRecorder; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; public enum WiModsTestHelper { @@ -102,7 +104,7 @@ public static void waitUntil(String event, break; } - if(startTime.isAfter(timeout)) + if(LocalDateTime.now().isAfter(timeout)) throw new RuntimeException( "Waiting until " + event + " took too long"); @@ -168,6 +170,16 @@ public static void waitForWorldTicks(int ticks) Duration.ofMillis(ticks * 100).plusMinutes(5)); } + public static void waitForBlock(int relX, int relY, int relZ, Block block) + { + BlockPos pos = + submitAndGet(mc -> mc.player.getBlockPos().add(relX, relY, relZ)); + waitUntil( + "block at ~" + relX + " ~" + relY + " ~" + relZ + " (" + + pos.toShortString() + ") is " + block, + mc -> mc.world.getBlockState(pos).getBlock() == block); + } + /** * Waits for 50ms and then takes a screenshot with the given name. */ @@ -305,6 +317,18 @@ public static void setTextFieldText(int index, String text) }); } + public static void setKeyPressState(int key, boolean pressed) + { + submitAndWait(mc -> mc.keyboard.onKey(mc.getWindow().getHandle(), key, + 0, pressed ? 1 : 0, 0)); + } + + public static void scrollMouse(int horizontal, int vertical) + { + submitAndWait(mc -> mc.mouse.onMouseScroll(mc.getWindow().getHandle(), + horizontal, vertical)); + } + public static void closeScreen() { submitAndWait(mc -> mc.setScreen(null)); diff --git a/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java b/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java index d5bdd54..658bb0e 100644 --- a/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java +++ b/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java @@ -145,7 +145,7 @@ private void testZoomInWorld() int scrollsNeededFor50x = MathHelper.ceil(Math.log(50 / 3) / Math.log(1.1)); for(int i = 0; i < scrollsNeededFor50x; i++) - scrollUp(); + scrollMouse(0, 1); waitForWorldTicks(1); takeScreenshot("chicken_50x_zoom"); @@ -158,16 +158,4 @@ private void testZoomInWorld() setKeyPressState(GLFW.GLFW_KEY_V, false); waitForWorldTicks(1); } - - private void setKeyPressState(int key, boolean pressed) - { - submitAndWait(mc -> mc.keyboard.onKey(mc.getWindow().getHandle(), key, - 0, pressed ? 1 : 0, 0)); - } - - private void scrollUp() - { - submitAndWait( - mc -> mc.mouse.onMouseScroll(mc.getWindow().getHandle(), 0, 1)); - } } From ce644b8f42eac4dc147d4fc0378415b82997b316 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Mon, 6 Jan 2025 16:03:09 +0100 Subject: [PATCH 40/54] Switch to GabrielBB's xvfb-action --- .github/workflows/gradle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index b76e252..46e1b3d 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -100,7 +100,7 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY - name: Run the mod and take screenshots - uses: modmuss50/xvfb-action@c56c7da0c8fc9a7cb5df2e50dd2a43a80b64c5cb + uses: GabrielBB/xvfb-action@v1.7 with: run: ./gradlew runEndToEndTest --stacktrace --warning-mode=fail From ac6bf18e690f8fff304aa45f398d4dcc3407a9f4 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Tue, 7 Jan 2025 20:58:13 +0100 Subject: [PATCH 41/54] Add a test that looks at the zoom keybind --- .../zoom/test/WiModsTestHelper.java | 52 ++++++++++++------- .../zoom/test/WiZoomTestClient.java | 27 ++++++++++ src/main/resources/wi-zoom.accesswidener | 4 +- 3 files changed, 63 insertions(+), 20 deletions(-) diff --git a/src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java b/src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java index 00961b5..f2eccfd 100644 --- a/src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java +++ b/src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java @@ -30,6 +30,7 @@ import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ClickableWidget; import net.minecraft.client.gui.widget.CyclingButtonWidget; +import net.minecraft.client.gui.widget.OptionListWidget; import net.minecraft.client.gui.widget.TextFieldWidget; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.option.Perspective; @@ -69,7 +70,7 @@ public static T submitAndGet(Function function) /** * Waits for the given duration. */ - public static void wait(Duration duration) + public static void waitFor(Duration duration) { try { @@ -108,7 +109,7 @@ public static void waitUntil(String event, throw new RuntimeException( "Waiting until " + event + " took too long"); - wait(Duration.ofMillis(50)); + waitFor(Duration.ofMillis(50)); } } @@ -194,7 +195,7 @@ public static void takeScreenshot(String name) */ public static void takeScreenshot(String name, Duration delay) { - wait(delay); + waitFor(delay); String count = String.format("%02d", screenshotCounter.incrementAndGet()); @@ -265,28 +266,41 @@ public static void clickButton(String translationKey) for(Drawable drawable : screen.drawables) { - if(!(drawable instanceof ClickableWidget widget)) - continue; - - if(widget instanceof ButtonWidget button - && buttonText.equals(button.getMessage().getString())) - { - button.onPress(); - return true; - } - - if(widget instanceof CyclingButtonWidget button - && buttonText.equals(button.optionText.getString())) - { - button.onPress(); - return true; - } + if(drawable instanceof ClickableWidget widget) + if(clickButtonInWidget(widget, buttonText)) + return true; + + if(drawable instanceof OptionListWidget list) + for(OptionListWidget.WidgetEntry entry : list.children()) + for(ClickableWidget widget : entry.widgets) + if(clickButtonInWidget(widget, buttonText)) + return true; } return false; }); } + private static boolean clickButtonInWidget(ClickableWidget widget, + String buttonText) + { + if(widget instanceof ButtonWidget button + && buttonText.equals(button.getMessage().getString())) + { + button.onPress(); + return true; + } + + if(widget instanceof CyclingButtonWidget button + && buttonText.equals(button.optionText.getString())) + { + button.onPress(); + return true; + } + + return false; + } + /** * Types the given text into the nth text field on the current screen, or * fails after 10 seconds. diff --git a/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java b/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java index 658bb0e..6111d6b 100644 --- a/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java +++ b/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java @@ -18,6 +18,9 @@ import net.minecraft.SharedConstants; import net.minecraft.client.gui.screen.AccessibilityOnboardingScreen; import net.minecraft.client.gui.screen.TitleScreen; +import net.minecraft.client.gui.screen.option.ControlsOptionsScreen; +import net.minecraft.client.gui.screen.option.KeybindsScreen; +import net.minecraft.client.gui.screen.option.OptionsScreen; import net.minecraft.client.gui.screen.world.CreateWorldScreen; import net.minecraft.client.gui.screen.world.SelectWorldScreen; import net.minecraft.util.math.MathHelper; @@ -120,7 +123,31 @@ private void runTests() openGameMenu(); takeScreenshot("game_menu"); + System.out.println("Clicking Options button"); + clickButton("menu.options"); + waitForScreen(OptionsScreen.class); + System.out.println("Reached options screen"); + takeScreenshot("options_screen", Duration.ZERO); + + System.out.println("Clicking Controls button"); + clickButton("options.controls"); + waitForScreen(ControlsOptionsScreen.class); + System.out.println("Reached controls screen"); + takeScreenshot("controls_screen", Duration.ZERO); + + System.out.println("Clicking Key Binds button"); + clickButton("controls.keybinds"); + waitForScreen(KeybindsScreen.class); + System.out.println("Reached keybinds screen"); + // Scroll down to the bottom + for(int i = 0; i < 100; i++) + scrollMouse(0, -1); + takeScreenshot("key_binds_screen", Duration.ZERO); + System.out.println("Returning to title screen"); + clickButton("gui.done"); + clickButton("gui.done"); + clickButton("gui.done"); clickButton("menu.returnToMenu"); waitForScreen(TitleScreen.class); diff --git a/src/main/resources/wi-zoom.accesswidener b/src/main/resources/wi-zoom.accesswidener index 70c3a70..8746392 100644 --- a/src/main/resources/wi-zoom.accesswidener +++ b/src/main/resources/wi-zoom.accesswidener @@ -1,5 +1,7 @@ accessWidener v1 named +accessible class net/minecraft/client/gui/widget/OptionListWidget$WidgetEntry +accessible method net/minecraft/client/Mouse onMouseScroll (JDD)V accessible field net/minecraft/client/gui/screen/Screen drawables Ljava/util/List; accessible field net/minecraft/client/gui/screen/TitleScreen doBackgroundFade Z accessible field net/minecraft/client/gui/widget/CyclingButtonWidget optionText Lnet/minecraft/text/Text; -accessible method net/minecraft/client/Mouse onMouseScroll (JDD)V +accessible field net/minecraft/client/gui/widget/OptionListWidget$WidgetEntry widgets Ljava/util/List; From b5cfc2c3964e5301df9e320bf9fcc5e8626a78fd Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Tue, 7 Jan 2025 22:52:52 +0100 Subject: [PATCH 42/54] Add tests for changing the keybind and trying to zoom in inventory --- .../zoom/test/WiModsTestHelper.java | 48 ++++++++++++++ .../zoom/test/WiZoomTestClient.java | 62 ++++++++++++++++--- src/main/resources/wi-zoom.accesswidener | 2 + 3 files changed, 103 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java b/src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java index f2eccfd..2f24469 100644 --- a/src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java +++ b/src/main/java/net/wurstclient/zoom/test/WiModsTestHelper.java @@ -26,6 +26,9 @@ import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.TitleScreen; import net.minecraft.client.gui.screen.ingame.InventoryScreen; +import net.minecraft.client.gui.screen.option.ControlsListWidget; +import net.minecraft.client.gui.screen.option.ControlsListWidget.Entry; +import net.minecraft.client.gui.screen.option.KeybindsScreen; import net.minecraft.client.gui.screen.world.LevelLoadingScreen; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ClickableWidget; @@ -281,6 +284,51 @@ public static void clickButton(String translationKey) }); } + /** + * Clicks the edit button for the key bind with the given translation key, + * or fails after 10 seconds. + * + *

+ * Must be called from the key binds screen. + */ + public static void clickEditKeybindButton(String translationKey) + { + waitUntil("edit button for " + translationKey + " is visible", mc -> { + Screen screen = mc.currentScreen; + if(!(screen instanceof KeybindsScreen)) + throw new RuntimeException( + "clickEditKeybindButton() must be called from the Key Binds screen. Current screen: " + + screen); + + for(Drawable drawable : screen.drawables) + { + if(!(drawable instanceof ControlsListWidget list)) + continue; + + for(Entry entry : list.children()) + { + if(!(entry instanceof ControlsListWidget.KeyBindingEntry kbEntry)) + continue; + + if(!translationKey + .equals(kbEntry.binding.getTranslationKey())) + continue; + + int x = kbEntry.editButton.getX() + list.getX() + + kbEntry.editButton.getWidth() / 2; + int y = kbEntry.editButton.getY() + + kbEntry.editButton.getHeight() / 2; + System.out.println("Clicking at " + x + ", " + y); + screen.mouseClicked(x, y, 0); + screen.mouseReleased(x, y, 0); + return true; + } + } + + return false; + }); + } + private static boolean clickButtonInWidget(ClickableWidget widget, String buttonText) { diff --git a/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java b/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java index 6111d6b..b8a1699 100644 --- a/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java +++ b/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java @@ -24,6 +24,7 @@ import net.minecraft.client.gui.screen.world.CreateWorldScreen; import net.minecraft.client.gui.screen.world.SelectWorldScreen; import net.minecraft.util.math.MathHelper; +import net.wurstclient.zoom.WiZoom; public final class WiZoomTestClient implements ClientModInitializer { @@ -104,7 +105,12 @@ private void runTests() System.out.println("Opening inventory"); openInventory(); + // Try to zoom in inventory to confirm it does nothing + setKeyPressState(GLFW.GLFW_KEY_V, true); + waitForWorldTicks(1); takeScreenshot("inventory"); + setKeyPressState(GLFW.GLFW_KEY_V, false); + waitForWorldTicks(1); System.out.println("Closing inventory"); closeScreen(); @@ -144,13 +150,30 @@ private void runTests() scrollMouse(0, -1); takeScreenshot("key_binds_screen", Duration.ZERO); - System.out.println("Returning to title screen"); + System.out.println("Changing zoom keybind to B"); + clickEditKeybindButton("key.wi_zoom.zoom"); + setKeyPressState(GLFW.GLFW_KEY_B, true); + setKeyPressState(GLFW.GLFW_KEY_B, false); + takeScreenshot("zoom_keybind_changed"); + + System.out.println("Closing screens"); clickButton("gui.done"); clickButton("gui.done"); clickButton("gui.done"); + clickButton("menu.returnToGame"); + + testZoomWithChangedKeybind(); + + System.out.println("Returning to title screen"); + openGameMenu(); clickButton("menu.returnToMenu"); waitForScreen(TitleScreen.class); + System.out.println("Changing zoom keybind back to V"); + submitAndWait(mc -> WiZoom.INSTANCE.getZoomKey() + .setBoundKey(WiZoom.INSTANCE.getZoomKey().getDefaultKey())); + submitAndWait(mc -> mc.options.write()); + System.out.println("Stopping the game"); clickButton("menu.quit"); } @@ -168,21 +191,42 @@ private void testZoomInWorld() waitForWorldTicks(1); takeScreenshot("chicken_3x_zoom"); - // Scroll up to increase zoom + scrollUpToMaxZoom(); + takeScreenshot("chicken_50x_zoom"); + + assertSelectedSlotIsZero(); + + // Release V to disable zoom + setKeyPressState(GLFW.GLFW_KEY_V, false); + waitForWorldTicks(1); + } + + private void testZoomWithChangedKeybind() + { + setKeyPressState(GLFW.GLFW_KEY_B, true); + waitForWorldTicks(1); + + scrollUpToMaxZoom(); + takeScreenshot("custom_keybind_50x_zoom"); + assertSelectedSlotIsZero(); + + setKeyPressState(GLFW.GLFW_KEY_B, false); + waitForWorldTicks(1); + } + + private void scrollUpToMaxZoom() + { int scrollsNeededFor50x = MathHelper.ceil(Math.log(50 / 3) / Math.log(1.1)); for(int i = 0; i < scrollsNeededFor50x; i++) scrollMouse(0, 1); waitForWorldTicks(1); - takeScreenshot("chicken_50x_zoom"); - - // Confirm selected slot is still zero + } + + private void assertSelectedSlotIsZero() + { if(submitAndGet(mc -> mc.player.getInventory().selectedSlot != 0)) throw new RuntimeException( "Scrolling up while zooming changed the selected slot"); - - // Release V to disable zoom - setKeyPressState(GLFW.GLFW_KEY_V, false); - waitForWorldTicks(1); } } diff --git a/src/main/resources/wi-zoom.accesswidener b/src/main/resources/wi-zoom.accesswidener index 8746392..280350b 100644 --- a/src/main/resources/wi-zoom.accesswidener +++ b/src/main/resources/wi-zoom.accesswidener @@ -3,5 +3,7 @@ accessible class net/minecraft/client/gui/widget/OptionListWidget$WidgetEntry accessible method net/minecraft/client/Mouse onMouseScroll (JDD)V accessible field net/minecraft/client/gui/screen/Screen drawables Ljava/util/List; accessible field net/minecraft/client/gui/screen/TitleScreen doBackgroundFade Z +accessible field net/minecraft/client/gui/screen/option/ControlsListWidget$KeyBindingEntry editButton Lnet/minecraft/client/gui/widget/ButtonWidget; +accessible field net/minecraft/client/gui/screen/option/ControlsListWidget$KeyBindingEntry binding Lnet/minecraft/client/option/KeyBinding; accessible field net/minecraft/client/gui/widget/CyclingButtonWidget optionText Lnet/minecraft/text/Text; accessible field net/minecraft/client/gui/widget/OptionListWidget$WidgetEntry widgets Ljava/util/List; From 9837a5db36ded36a313c446b8b5a4ae268d82ace Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Tue, 7 Jan 2025 22:57:48 +0100 Subject: [PATCH 43/54] Add default delay to key_binds_screen screenshot --- src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java b/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java index b8a1699..bb97471 100644 --- a/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java +++ b/src/main/java/net/wurstclient/zoom/test/WiZoomTestClient.java @@ -148,7 +148,7 @@ private void runTests() // Scroll down to the bottom for(int i = 0; i < 100; i++) scrollMouse(0, -1); - takeScreenshot("key_binds_screen", Duration.ZERO); + takeScreenshot("key_binds_screen"); System.out.println("Changing zoom keybind to B"); clickEditKeybindButton("key.wi_zoom.zoom"); From 9eefff5b8c9a8cccb714372ab449d618d6a1ae97 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Tue, 7 Jan 2025 23:07:58 +0100 Subject: [PATCH 44/54] Change version to 1.6 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index efcd7f7..baabee9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ loader_version=0.16.9 fabric_version=0.110.5+1.21.4 # Mod Properties -mod_version = 1.5-MC1.21.4 +mod_version = 1.6-MC1.21.4 maven_group = net.wurstclient.zoom archives_base_name = WI-Zoom From c0eea3b8ed25f32b032a8e74811b5f7d2e18ca2d Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Tue, 7 Jan 2025 23:39:16 +0100 Subject: [PATCH 45/54] Add check_translations workflow --- .github/workflows/check_translations.yml | 32 +++++++ .gitignore | 3 + scripts/check_translations.py | 96 +++++++++++++++++++ scripts/util.py | 17 ++++ .../resources/intentionally_untranslated.json | 8 ++ 5 files changed, 156 insertions(+) create mode 100644 .github/workflows/check_translations.yml create mode 100644 scripts/check_translations.py create mode 100644 scripts/util.py create mode 100644 src/main/resources/intentionally_untranslated.json diff --git a/.github/workflows/check_translations.yml b/.github/workflows/check_translations.yml new file mode 100644 index 0000000..986295d --- /dev/null +++ b/.github/workflows/check_translations.yml @@ -0,0 +1,32 @@ +name: Check Translations + +on: + push: + branches-ignore: + - "dependabot/**" + tags-ignore: + - "**" + paths: + - "src/main/resources/assets/wi_zoom/lang/**.json" + - "src/main/resources/intentionally_untranslated.json" + pull_request: + paths: + - "src/main/resources/assets/wi_zoom/lang/**.json" + - "src/main/resources/intentionally_untranslated.json" + workflow_dispatch: + +jobs: + check_translations: + runs-on: ubuntu-latest + steps: + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Run check_translations.py + run: python scripts/check_translations.py diff --git a/.gitignore b/.gitignore index 2a4d72b..b38657f 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,9 @@ run/ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* +# python +*.pyc + desktop.ini # (neo)forge diff --git a/scripts/check_translations.py b/scripts/check_translations.py new file mode 100644 index 0000000..c9c2ed1 --- /dev/null +++ b/scripts/check_translations.py @@ -0,0 +1,96 @@ +import util +from pathlib import Path + +translations_dir = Path("src") / "main" / "resources" / "assets" / "wi_zoom" / "lang" + + +def show_translation_stats(en_us: dict, translations: dict): + """Render a table of the current translation progress for each language.""" + util.add_github_summary("| Language | Translated | % |") + util.add_github_summary("| --- | --- | --- |") + util.add_github_summary(f"| en_us | {len(en_us)} | 100.00% |") + for lang, data in translations.items(): + util.add_github_summary(f"| {lang} | {len(data)} | {len(data) / len(en_us) * 100:.2f}% |") + util.add_github_summary("") + + +def check_extra_keys(en_us: dict, translations: dict): + """Check if any translation files contain keys that don't exist in the original.""" + extra_keys_found = False + for lang, data in translations.items(): + extra_keys = set(data.keys()) - set(en_us.keys()) + if extra_keys: + extra_keys_found = True + util.add_github_summary( + f"⚠ {lang}.json contains translations that don't exist in en_us.json ({len(extra_keys)} found):" + ) + for key in extra_keys: + util.add_github_summary(f"- {key}") + if extra_keys_found: + raise Exception("Found extra keys in one or more translation files, see summary") + util.add_github_summary("✅ No extra keys found") + + +def check_untranslated_strings(en_us: dict, translations: dict): + """Check if any translation files contain untranslated strings.""" + untranslated_strings_found = False + intentionally_untranslated = util.read_json_file( + Path("src") / "main" / "resources" / "intentionally_untranslated.json" + ) + + for lang, data in translations.items(): + untranslated_strings = set() + for key, value in data.items(): + if value == en_us[key]: + if lang in intentionally_untranslated and key in intentionally_untranslated[lang]: + continue + untranslated_strings.add(key) + if untranslated_strings: + untranslated_strings_found = True + util.add_github_summary( + f"⚠ {lang}.json contains strings that are identical to en_us.json ({len(untranslated_strings)} found):" + ) + for key in untranslated_strings: + util.add_github_summary(f"- {key}: {en_us[key]}") + util.add_github_summary( + "\nIf this is intentional, add the affected key(s) to intentionally_untranslated.json:" + ) + util.add_github_summary("```json") + util.add_github_summary(f' "{lang}": [') + for key in untranslated_strings: + util.add_github_summary(f' "{key}"') + util.add_github_summary(" ]") + util.add_github_summary("```") + + if untranslated_strings_found: + raise Exception("Found untranslated strings in one or more translation files, see summary") + util.add_github_summary("✅ No accidentally untranslated strings found") + + +def check_order_of_strings(en_us: dict, translations: dict): + """Check if the strings in each translation file are in the same order as in en_us.json.""" + for lang, data in translations.items(): + en_us_keys_present_in_translation = [key for key in en_us.keys() if key in data.keys()] + translation_keys_present_in_en_us = [key for key in data.keys() if key in en_us.keys()] + if en_us_keys_present_in_translation != translation_keys_present_in_en_us: + raise Exception(f"⚠ The order of strings in {lang}.json is different from en_us.json") + util.add_github_summary("✅ The order of strings in each translation file matches en_us.json") + + +def main(): + en_us = util.read_json_file(translations_dir / "en_us.json") + translations = {} + for path in sorted(translations_dir.rglob("*.json"), key=lambda x: x.name): + if path.is_file() and path.name != "en_us.json": + lang = path.name.removesuffix(".json") + data = util.read_json_file(path) + translations[lang] = data + + show_translation_stats(en_us, translations) + check_extra_keys(en_us, translations) + check_untranslated_strings(en_us, translations) + check_order_of_strings(en_us, translations) + + +if __name__ == "__main__": + main() diff --git a/scripts/util.py b/scripts/util.py new file mode 100644 index 0000000..807fce1 --- /dev/null +++ b/scripts/util.py @@ -0,0 +1,17 @@ +import json +import os +from pathlib import Path + + +def read_json_file(path: Path) -> dict: + """Read a JSON data file.""" + return json.loads(path.read_text(encoding="utf-8")) + + +def add_github_summary(summary: str): + """Add a line to the GitHub Actions summary for the current step.""" + if "GITHUB_STEP_SUMMARY" not in os.environ: + print(summary) + return + with open(os.environ["GITHUB_STEP_SUMMARY"], "a") as summary_file: + print(summary, file=summary_file) diff --git a/src/main/resources/intentionally_untranslated.json b/src/main/resources/intentionally_untranslated.json new file mode 100644 index 0000000..c5544a7 --- /dev/null +++ b/src/main/resources/intentionally_untranslated.json @@ -0,0 +1,8 @@ +{ + "de_de": [ + "key.wi_zoom.zoom" + ], + "fr_fr": [ + "key.wi_zoom.zoom" + ] +} From 507c850926a8390f639ff1b9109a4e5c4a727f7b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 23:01:49 +0000 Subject: [PATCH 46/54] Bump com.diffplug.spotless from 6.25.0 to 7.0.1 Bumps com.diffplug.spotless from 6.25.0 to 7.0.1. --- updated-dependencies: - dependency-name: com.diffplug.spotless dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 20cc89b..ebd0282 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { plugins { id "fabric-loom" version "1.9-SNAPSHOT" id "me.modmuss50.mod-publish-plugin" version "0.8.4" - id "com.diffplug.spotless" version "6.25.0" + id "com.diffplug.spotless" version "7.0.1" } def ENV = System.getenv() From 6e4fe88f6002ceffd5de2dbf7511d41a0359743d Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Wed, 8 Jan 2025 00:58:28 +0100 Subject: [PATCH 47/54] Update CurseForge game version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index baabee9..a6cee7d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,6 +18,6 @@ maven_group = net.wurstclient.zoom archives_base_name = WI-Zoom # CurseForge -cf_game_version=1.21.4-Snapshot +cf_game_version=1.21.4 # Dependencies From daf55df99f7c827f0f9ad8ab34d14ceeafb67d1c Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Wed, 8 Jan 2025 00:58:53 +0100 Subject: [PATCH 48/54] Update Fabric stuff --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index a6cee7d..659169c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,11 +6,11 @@ org.gradle.parallel=true # check these at https://fabricmc.net/develop/ and # https://modrinth.com/mod/fabric-api/versions minecraft_version=1.21.4 -yarn_mappings=1.21.4+build.1 +yarn_mappings=1.21.4+build.8 loader_version=0.16.9 # Fabric API -fabric_version=0.110.5+1.21.4 +fabric_version=0.114.1+1.21.4 # Mod Properties mod_version = 1.6-MC1.21.4 From 0f9202da0ec7dcd2db269b1896bb81af08531b20 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Wed, 8 Jan 2025 01:28:12 +0100 Subject: [PATCH 49/54] Remove extra spaces in gradle.properties --- gradle.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 659169c..0ee6d84 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,9 +13,9 @@ loader_version=0.16.9 fabric_version=0.114.1+1.21.4 # Mod Properties -mod_version = 1.6-MC1.21.4 -maven_group = net.wurstclient.zoom -archives_base_name = WI-Zoom +mod_version=1.6-MC1.21.4 +maven_group=net.wurstclient.zoom +archives_base_name=WI-Zoom # CurseForge cf_game_version=1.21.4 From c45b1836fc57164ebd5f4a8a15b5fd71d4eb1148 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Wed, 8 Jan 2025 01:29:12 +0100 Subject: [PATCH 50/54] Update publish workflow --- .github/workflows/publish.yml | 64 +++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 95aadb9..d22dda1 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -4,6 +4,8 @@ run-name: "Publish release from ${{ github.ref_name }} branch" permissions: # Needed to push the tag. contents: write + # Needed to close the milestone. + issues: write on: workflow_dispatch: @@ -72,7 +74,7 @@ jobs: - name: Create and push tag run: | - MOD_VERSION=$(grep "mod_version" gradle.properties | cut -d'=' -f2 | tr -d ' \r') + MOD_VERSION=$(grep "^mod_version=" gradle.properties | cut -d'=' -f2 | tr -d ' \r') git config --global user.name "Wurst-Bot" git config --global user.email "contact.wurstimperium@gmail.com" git tag "v$MOD_VERSION" @@ -92,7 +94,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.MCX_PUBLISH_TOKEN }} run: ./gradlew github --stacktrace - - name: Publish to CurseForge + - name: Publish to CurseForge if: ${{ inputs.publish_curseforge }} run: ./gradlew publishCurseforge --stacktrace @@ -100,27 +102,53 @@ jobs: id: cf_file_id if: ${{ inputs.publish_curseforge }} run: | - file_id=$(./gradlew getCurseforgeId | grep -o 'CURSEFORGE_FILE_ID=[0-9]*' | grep -o '[0-9]*') + file_id=$(./gradlew getCurseforgeId -x publishCurseforge | grep -o 'CURSEFORGE_FILE_ID=[0-9]*' | grep -o '[0-9]*') echo "file_id=$file_id" >> "$GITHUB_OUTPUT" - echo "CurseForge file ID: `$file_id`" >> $GITHUB_STEP_SUMMARY + echo "CurseForge file ID: \`$file_id\`" >> $GITHUB_STEP_SUMMARY - name: Publish to Modrinth if: ${{ inputs.publish_modrinth }} run: ./gradlew publishModrinth --stacktrace - - name: Trigger website update + - name: Build website update inputs + id: website_inputs if: ${{ inputs.update_website && inputs.publish_curseforge }} - env: - GH_TOKEN: ${{ secrets.WIMODS_NET_PUBLISH_TOKEN }} run: | - MOD_VERSION=$(grep "mod_version" gradle.properties | cut -d'=' -f2 | tr -d ' \r' | sed 's/-MC.*$//') - MC_VERSION=$(grep "minecraft_version" gradle.properties | cut -d'=' -f2 | tr -d ' \r') - FAPI_VERSION=$(grep "fabric_version" gradle.properties | cut -d'=' -f2 | tr -d ' \r') - gh workflow run add_mod_port.yml \ - -R Wurst-Imperium/wimods.net \ - -f mod="wi-zoom" \ - -f modloader="fabric" \ - -f mod_version="$MOD_VERSION" \ - -f mc_version="$MC_VERSION" \ - -f fapi_version="$FAPI_VERSION" \ - -f file_id="${{ steps.cf_file_id.outputs.file_id }}" + MOD_VERSION=$(grep "^mod_version=" gradle.properties | cut -d'=' -f2 | tr -d ' \r' | sed 's/-MC.*$//') + MC_VERSION=$(grep "^minecraft_version=" gradle.properties | cut -d'=' -f2 | tr -d ' \r') + FAPI_VERSION=$(grep "^fabric_version=" gradle.properties | cut -d'=' -f2 | tr -d ' \r') + JSON_STRING=$(cat << EOF + { + "mod": "wi-zoom", + "modloader": "fabric", + "mod_version": "$MOD_VERSION", + "mc_version": "$MC_VERSION", + "fapi_version": "$FAPI_VERSION", + "file_id": "${{ steps.cf_file_id.outputs.file_id }}" + } + EOF + ) + # Convert to single line and escape quotes + echo "json=${JSON_STRING//$'\n'/}" >> "$GITHUB_OUTPUT" + + - name: Trigger website update + id: website_dispatch + if: ${{ inputs.update_website && inputs.publish_curseforge }} + uses: codex-/return-dispatch@v2 + with: + token: ${{ secrets.WIMODS_NET_PUBLISH_TOKEN }} + owner: Wurst-Imperium + repo: wimods.net + ref: master + workflow: add_mod_port.yml + workflow_inputs: ${{ steps.website_inputs.outputs.json }} + + - name: Wait for website update to finish (run ${{ steps.website_dispatch.outputs.run_id }}) + if: ${{ inputs.update_website && inputs.publish_curseforge }} + uses: codex-/await-remote-run@v1 + with: + token: ${{ secrets.WIMODS_NET_PUBLISH_TOKEN }} + owner: Wurst-Imperium + repo: wimods.net + run_id: ${{ steps.website_dispatch.outputs.run_id }} + run_timeout_seconds: 600 # 10 minutes From 972955996adb47d4e52516b644119c4cc248224a Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Wed, 8 Jan 2025 16:49:59 +0100 Subject: [PATCH 51/54] Add distinct_id to auto_snapshot_update and publish workflows --- .github/workflows/auto_snapshot_update.yml | 6 ++++++ .github/workflows/publish.yml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/.github/workflows/auto_snapshot_update.yml b/.github/workflows/auto_snapshot_update.yml index 96bb764..4206daf 100644 --- a/.github/workflows/auto_snapshot_update.yml +++ b/.github/workflows/auto_snapshot_update.yml @@ -19,6 +19,9 @@ on: cf_game_version: description: "CurseForge GameVersion" required: true + distinct_id: + description: "Automatically set by the return-dispatch action (leave blank if running manually)" + required: false permissions: # To push changes to the new snapshot branch. @@ -31,6 +34,9 @@ jobs: runs-on: ubuntu-latest steps: + - name: Echo distinct ID ${{ github.event.inputs.distinct_id }} + run: echo ${{ github.event.inputs.distinct_id }} + - name: Checkout repository uses: actions/checkout@v4 with: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d22dda1..495880d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -40,6 +40,9 @@ on: required: false type: boolean default: false + distinct_id: + description: "Automatically set by the return-dispatch action (leave blank if running manually)" + required: false jobs: publish: @@ -51,6 +54,9 @@ jobs: MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} steps: + - name: Echo distinct ID ${{ github.event.inputs.distinct_id }} + run: echo ${{ github.event.inputs.distinct_id }} + - name: Checkout repository uses: actions/checkout@v4 with: From 5cfa2e638cc8f29fdb1276d295d79241edde5da4 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Sat, 11 Jan 2025 23:46:02 +0100 Subject: [PATCH 52/54] Use 'leadingSpacesToTabs' instead of 'indentWithTabs' in build.gradle --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ebd0282..b70cdd1 100644 --- a/build.gradle +++ b/build.gradle @@ -120,7 +120,7 @@ spotless { lineEndings("WINDOWS") java { removeUnusedImports() - indentWithTabs() + leadingSpacesToTabs() trimTrailingWhitespace() eclipse().configFile(file("codestyle/formatter.xml")) } From 44177ccfabc379da535ec6c0edf38bd1ee9d4a9f Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Sun, 12 Jan 2025 21:35:38 +0100 Subject: [PATCH 53/54] Update GHA workflows --- .github/workflows/auto_snapshot_update.yml | 36 ++-- .github/workflows/dependency_graph.yml | 3 +- .github/workflows/gradle.yml | 12 +- .github/workflows/publish.yml | 208 ++++++++++----------- .github/workflows/stale.yml | 56 +++--- 5 files changed, 165 insertions(+), 150 deletions(-) diff --git a/.github/workflows/auto_snapshot_update.yml b/.github/workflows/auto_snapshot_update.yml index 4206daf..44b3862 100644 --- a/.github/workflows/auto_snapshot_update.yml +++ b/.github/workflows/auto_snapshot_update.yml @@ -78,23 +78,24 @@ jobs: git checkout -b $BRANCH_NAME echo "Created and checked out new branch: $BRANCH_NAME" fi - shell: bash - name: Run migrateMappings task run: | ./gradlew migrateMappings --mappings ${{ github.event.inputs.yarn_mappings }} - shell: bash - name: Replace src/main/java with remapped files run: | rm -rf ./src/main/java mv ./remappedSrc ./src/main/java - shell: bash - name: Update version constants run: | - python scripts/update_version_constants.py "${{ github.event.inputs.mc_version }}" "${{ github.event.inputs.yarn_mappings }}" "${{ github.event.inputs.fabric_loader }}" "${{ github.event.inputs.fapi_version }}" "${{ github.event.inputs.cf_game_version }}" - shell: bash + python scripts/update_version_constants.py \ + "${{ github.event.inputs.mc_version }}" \ + "${{ github.event.inputs.yarn_mappings }}" \ + "${{ github.event.inputs.fabric_loader }}" \ + "${{ github.event.inputs.fapi_version }}" \ + "${{ github.event.inputs.cf_game_version }}" # To fix any style issues that the migration scripts might cause - name: Run spotlessApply task @@ -107,13 +108,22 @@ jobs: git add . git commit -m "[Wurst-Bot] Update to ${{ github.event.inputs.mc_version }}" git push --set-upstream origin ${{ github.event.inputs.mc_version }} - shell: bash - # For some reason the commit above doesn't automatically trigger the CI - # workflow, so we need to explicitly start it here. - name: Trigger CI on the new branch - env: - GH_TOKEN: ${{ github.token }} - run: | - gh workflow run gradle.yml --ref ${{ github.event.inputs.mc_version }} - shell: bash + id: ci_dispatch + uses: codex-/return-dispatch@v2 + with: + token: ${{ github.token }} + owner: Wurst-Imperium + repo: WI-Zoom + ref: ${{ github.event.inputs.mc_version }} + workflow: gradle.yml + + - name: Wait for CI to finish (run ${{ steps.ci_dispatch.outputs.run_id }}) + uses: codex-/await-remote-run@v1 + with: + token: ${{ github.token }} + owner: Wurst-Imperium + repo: WI-Zoom + run_id: ${{ steps.ci_dispatch.outputs.run_id }} + run_timeout_seconds: 600 # 10 minutes diff --git a/.github/workflows/dependency_graph.yml b/.github/workflows/dependency_graph.yml index 4d2765b..74a85a2 100644 --- a/.github/workflows/dependency_graph.yml +++ b/.github/workflows/dependency_graph.yml @@ -13,10 +13,11 @@ on: workflow_dispatch: permissions: + # Needed by the dependency-submission action. contents: write jobs: - dependency-submission: + dependency_graph: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 46e1b3d..44dde84 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -20,6 +20,10 @@ on: - "gradle**" - "*.gradle" workflow_dispatch: + inputs: + distinct_id: + description: "Automatically set by the return-dispatch action (leave blank if running manually)" + required: false jobs: build: @@ -29,6 +33,9 @@ jobs: IMGUR_CLIENT_ID: ${{ secrets.IMGUR_CLIENT_ID }} steps: + - name: Echo distinct ID ${{ github.event.inputs.distinct_id }} + run: echo ${{ github.event.inputs.distinct_id }} + - name: Checkout repository uses: actions/checkout@v4 @@ -85,7 +92,6 @@ jobs: - name: Add VirusTotal links to build summary if: ${{ env.VIRUSTOTAL_API_KEY && steps.virustotal.outputs.analysis }} - shell: bash run: | echo "

" >> $GITHUB_STEP_SUMMARY echo "🛡️ VirusTotal Scans" >> $GITHUB_STEP_SUMMARY @@ -122,21 +128,17 @@ jobs: echo "
" >> $GITHUB_STEP_SUMMARY echo "📸 Test Screenshots" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - for img in run/screenshots/*.png; do if [ -f "$img" ]; then filename=$(basename "$img") name_without_ext="${filename%.*}" - # Upload to Imgur response=$(curl -s -X POST \ -H "Authorization: Client-ID $IMGUR_CLIENT_ID" \ -F "image=@$img" \ https://api.imgur.com/3/image) - # Extract the URL from the response url=$(echo $response | grep -o '"link":"[^"]*"' | cut -d'"' -f4) - if [ ! -z "$url" ]; then # Convert underscores to spaces and capitalize first letter of each word title=$(echo "$name_without_ext" | tr '_' ' ' | awk '{for(i=1;i<=NF;i++)sub(/./,toupper(substr($i,1,1)),$i)}1') diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 495880d..cf8513b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -54,107 +54,107 @@ jobs: MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} steps: - - name: Echo distinct ID ${{ github.event.inputs.distinct_id }} - run: echo ${{ github.event.inputs.distinct_id }} - - - name: Checkout repository - uses: actions/checkout@v4 - with: - # Include all tags in case the new tag already exists. - fetch-tags: true - - - name: Set up Java 21 - uses: actions/setup-java@v4 - with: - java-version: "21" - distribution: "microsoft" - - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 - - - name: Build - run: ./gradlew build --stacktrace --warning-mode=fail - - - name: Create and push tag - run: | - MOD_VERSION=$(grep "^mod_version=" gradle.properties | cut -d'=' -f2 | tr -d ' \r') - git config --global user.name "Wurst-Bot" - git config --global user.email "contact.wurstimperium@gmail.com" - git tag "v$MOD_VERSION" - git push origin "v$MOD_VERSION" - - - name: Close milestone - if: ${{ inputs.close_milestone }} - run: ./gradlew closeMilestone --stacktrace - - - name: Upload backups - if: ${{ inputs.upload_backups }} - run: ./gradlew uploadBackups --stacktrace - - - name: Publish to GitHub - if: ${{ inputs.publish_github }} - env: - GITHUB_TOKEN: ${{ secrets.MCX_PUBLISH_TOKEN }} - run: ./gradlew github --stacktrace - - - name: Publish to CurseForge - if: ${{ inputs.publish_curseforge }} - run: ./gradlew publishCurseforge --stacktrace - - - name: Get CurseForge file ID - id: cf_file_id - if: ${{ inputs.publish_curseforge }} - run: | - file_id=$(./gradlew getCurseforgeId -x publishCurseforge | grep -o 'CURSEFORGE_FILE_ID=[0-9]*' | grep -o '[0-9]*') - echo "file_id=$file_id" >> "$GITHUB_OUTPUT" - echo "CurseForge file ID: \`$file_id\`" >> $GITHUB_STEP_SUMMARY - - - name: Publish to Modrinth - if: ${{ inputs.publish_modrinth }} - run: ./gradlew publishModrinth --stacktrace - - - name: Build website update inputs - id: website_inputs - if: ${{ inputs.update_website && inputs.publish_curseforge }} - run: | - MOD_VERSION=$(grep "^mod_version=" gradle.properties | cut -d'=' -f2 | tr -d ' \r' | sed 's/-MC.*$//') - MC_VERSION=$(grep "^minecraft_version=" gradle.properties | cut -d'=' -f2 | tr -d ' \r') - FAPI_VERSION=$(grep "^fabric_version=" gradle.properties | cut -d'=' -f2 | tr -d ' \r') - JSON_STRING=$(cat << EOF - { - "mod": "wi-zoom", - "modloader": "fabric", - "mod_version": "$MOD_VERSION", - "mc_version": "$MC_VERSION", - "fapi_version": "$FAPI_VERSION", - "file_id": "${{ steps.cf_file_id.outputs.file_id }}" - } - EOF - ) - # Convert to single line and escape quotes - echo "json=${JSON_STRING//$'\n'/}" >> "$GITHUB_OUTPUT" - - - name: Trigger website update - id: website_dispatch - if: ${{ inputs.update_website && inputs.publish_curseforge }} - uses: codex-/return-dispatch@v2 - with: - token: ${{ secrets.WIMODS_NET_PUBLISH_TOKEN }} - owner: Wurst-Imperium - repo: wimods.net - ref: master - workflow: add_mod_port.yml - workflow_inputs: ${{ steps.website_inputs.outputs.json }} - - - name: Wait for website update to finish (run ${{ steps.website_dispatch.outputs.run_id }}) - if: ${{ inputs.update_website && inputs.publish_curseforge }} - uses: codex-/await-remote-run@v1 - with: - token: ${{ secrets.WIMODS_NET_PUBLISH_TOKEN }} - owner: Wurst-Imperium - repo: wimods.net - run_id: ${{ steps.website_dispatch.outputs.run_id }} - run_timeout_seconds: 600 # 10 minutes + - name: Echo distinct ID ${{ github.event.inputs.distinct_id }} + run: echo ${{ github.event.inputs.distinct_id }} + + - name: Checkout repository + uses: actions/checkout@v4 + with: + # Include all tags in case the new tag already exists. + fetch-tags: true + + - name: Set up Java 21 + uses: actions/setup-java@v4 + with: + java-version: "21" + distribution: "microsoft" + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Build + run: ./gradlew build --stacktrace --warning-mode=fail + + - name: Create and push tag + run: | + MOD_VERSION=$(grep "^mod_version=" gradle.properties | cut -d'=' -f2 | tr -d ' \r') + git config --global user.name "Wurst-Bot" + git config --global user.email "contact.wurstimperium@gmail.com" + git tag "v$MOD_VERSION" + git push origin "v$MOD_VERSION" + + - name: Close milestone + if: ${{ inputs.close_milestone }} + run: ./gradlew closeMilestone --stacktrace + + - name: Upload backups + if: ${{ inputs.upload_backups }} + run: ./gradlew uploadBackups --stacktrace + + - name: Publish to GitHub + if: ${{ inputs.publish_github }} + env: + GITHUB_TOKEN: ${{ secrets.MCX_PUBLISH_TOKEN }} + run: ./gradlew github --stacktrace + + - name: Publish to CurseForge + if: ${{ inputs.publish_curseforge }} + run: ./gradlew publishCurseforge --stacktrace + + - name: Get CurseForge file ID + id: cf_file_id + if: ${{ inputs.publish_curseforge }} + run: | + file_id=$(./gradlew getCurseforgeId -x publishCurseforge | grep -o 'CURSEFORGE_FILE_ID=[0-9]*' | grep -o '[0-9]*') + echo "file_id=$file_id" >> "$GITHUB_OUTPUT" + echo "CurseForge file ID: \`$file_id\`" >> $GITHUB_STEP_SUMMARY + + - name: Publish to Modrinth + if: ${{ inputs.publish_modrinth }} + run: ./gradlew publishModrinth --stacktrace + + - name: Build website update inputs + id: website_inputs + if: ${{ inputs.update_website && inputs.publish_curseforge }} + run: | + MOD_VERSION=$(grep "^mod_version=" gradle.properties | cut -d'=' -f2 | tr -d ' \r' | sed 's/-MC.*$//') + MC_VERSION=$(grep "^minecraft_version=" gradle.properties | cut -d'=' -f2 | tr -d ' \r') + FAPI_VERSION=$(grep "^fabric_version=" gradle.properties | cut -d'=' -f2 | tr -d ' \r') + JSON_STRING=$(cat << EOF + { + "mod": "wi-zoom", + "modloader": "fabric", + "mod_version": "$MOD_VERSION", + "mc_version": "$MC_VERSION", + "fapi_version": "$FAPI_VERSION", + "file_id": "${{ steps.cf_file_id.outputs.file_id }}" + } + EOF + ) + # Convert to single line and escape quotes + echo "json=${JSON_STRING//$'\n'/}" >> "$GITHUB_OUTPUT" + + - name: Trigger website update + id: website_dispatch + if: ${{ inputs.update_website && inputs.publish_curseforge }} + uses: codex-/return-dispatch@v2 + with: + token: ${{ secrets.WIMODS_NET_PUBLISH_TOKEN }} + owner: Wurst-Imperium + repo: wimods.net + ref: master + workflow: add_mod_port.yml + workflow_inputs: ${{ steps.website_inputs.outputs.json }} + + - name: Wait for website update to finish (run ${{ steps.website_dispatch.outputs.run_id }}) + if: ${{ inputs.update_website && inputs.publish_curseforge }} + uses: codex-/await-remote-run@v1 + with: + token: ${{ secrets.WIMODS_NET_PUBLISH_TOKEN }} + owner: Wurst-Imperium + repo: wimods.net + run_id: ${{ steps.website_dispatch.outputs.run_id }} + run_timeout_seconds: 600 # 10 minutes diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index e7b27b7..a08ccc8 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -5,6 +5,7 @@ on: - cron: "30 1 * * 1-5" permissions: + # Both needed by the stale action. issues: write pull-requests: write @@ -13,30 +14,31 @@ jobs: runs-on: ubuntu-latest steps: - - name: Run stale bot - uses: actions/stale@v9 - with: - stale-issue-message: | - This issue has been open for a while with no recent activity. If this issue is still important to you, please add a comment within the next 7 days to keep it open. Otherwise, the issue will be automatically closed to free up time for other tasks. - - Issues should be closed if: - - They are duplicates of other issues - - There is not enough demand - - They are no longer relevant - - There are not enough details - stale-pr-message: | - This pull request has been open for a while with no recent activity. If you're still working on this or waiting for a review, please add a comment or commit within the next 7 days to keep it open. Otherwise, the pull request will be automatically closed to free up time for other tasks. - - Pull requests should be closed if: - - They have been superseded by another pull request - - They are out of scope or don't align with the project - - They have become obsolete due to other changes - - They have bugs or conflicts that won't be resolved - days-before-stale: 60 - days-before-close: 7 - exempt-issue-labels: "status:never-stale" - exempt-pr-labels: "status:never-stale" - stale-issue-label: "status:stale" - stale-pr-label: "status:stale" - operations-per-run: 30 - enable-statistics: true + - name: Run stale action + uses: actions/stale@v9 + with: + stale-issue-message: | + This issue has been open for a while with no recent activity. If this issue is still important to you, please add a comment within the next 7 days to keep it open. Otherwise, the issue will be automatically closed to free up time for other tasks. + + Issues should be closed if: + - They are duplicates of other issues + - There is not enough demand + - They are no longer relevant + - There are not enough details + stale-pr-message: | + This pull request has been open for a while with no recent activity. If you're still working on this or waiting for a review, please add a comment or commit within the next 7 days to keep it open. Otherwise, the pull request will be automatically closed to free up time for other tasks. + + Pull requests should be closed if: + - They have been superseded by another pull request + - They are out of scope or don't align with the project + - They have become obsolete due to other changes + - They have bugs or conflicts that won't be resolved + days-before-stale: 60 + days-before-close: 7 + exempt-issue-labels: "status:never-stale,status:confirmed" + exempt-pr-labels: "status:never-stale,status:confirmed,status:merged" + exempt-all-milestones: true + stale-issue-label: "status:stale" + stale-pr-label: "status:stale" + operations-per-run: 30 + enable-statistics: true From 7da725e11dcd9320efbbbfdef33828f00694aeb1 Mon Sep 17 00:00:00 2001 From: Alexander01998 Date: Sun, 12 Jan 2025 21:44:56 +0100 Subject: [PATCH 54/54] Fix intentionally_untranslated.json being included in the mod jar --- build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index b70cdd1..66640b9 100644 --- a/build.gradle +++ b/build.gradle @@ -113,6 +113,8 @@ jar { from("LICENSE") { rename {"${it}_${base.archivesName.get()}"} } + + exclude("intentionally_untranslated.json") } import com.diffplug.spotless.generic.LicenseHeaderStep