├── .gitattributes ├── .github ├── advanced-issue-labeler.yml └── workflows │ ├── label-issues.yaml │ ├── manage-labels.yaml │ ├── publish-release.yml │ └── publish-snapshot.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build.gradle ├── buildSrc ├── build.gradle └── src │ └── main │ └── groovy │ ├── multiloader-common.gradle │ └── multiloader-loader.gradle ├── common ├── build.gradle ├── dependencies.gradle └── src │ └── main │ ├── java │ └── net │ │ └── blay09 │ │ └── mods │ │ └── forgivingvoid │ │ ├── DamageOnFallMode.java │ │ ├── ForgivingVoid.java │ │ ├── ForgivingVoidConfig.java │ │ ├── ForgivingVoidFallThroughEvent.java │ │ └── mixin │ │ ├── CombatTrackerMixin.java │ │ ├── ServerGamePacketListenerImplAccessor.java │ │ ├── ServerPlayerAccessor.java │ │ └── ThrownTridentAccessor.java │ └── resources │ ├── assets │ └── forgivingvoid │ │ └── lang │ │ ├── en_us.json │ │ ├── es_es.json │ │ └── ko_kr.json │ ├── forgivingvoid.mixins.json │ ├── forgivingvoid.png │ └── pack.mcmeta ├── fabric ├── build.gradle ├── dependencies.gradle └── src │ └── main │ ├── java │ └── net │ │ └── blay09 │ │ └── mods │ │ └── forgivingvoid │ │ └── fabric │ │ └── FabricForgivingVoid.java │ └── resources │ ├── fabric.mod.json │ └── forgivingvoid.fabric.mixins.json ├── forge ├── build.gradle ├── dependencies.gradle └── src │ └── main │ ├── java │ └── net │ │ └── blay09 │ │ └── mods │ │ └── forgivingvoid │ │ └── ForgeForgivingVoid.java │ └── resources │ ├── META-INF │ └── mods.toml │ └── forgivingvoid.forge.mixins.json ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── modpage.md ├── neoforge ├── build.gradle ├── dependencies.gradle └── src │ └── main │ ├── java │ └── net │ │ └── blay09 │ │ └── mods │ │ └── forgivingvoid │ │ └── NeoForgeForgivingVoid.java │ └── resources │ ├── META-INF │ └── neoforge.mods.toml │ └── forgivingvoid.neoforge.mixins.json ├── repositories.gradle └── settings.gradle /.gitattributes: -------------------------------------------------------------------------------- 1 | # Disable autocrlf on generated files, they always generate with LF 2 | # Add any extra files or paths here to make git stop saying they 3 | # are changed when only line endings change. 4 | src/generated/**/.cache/cache text eol=lf 5 | src/generated/**/*.json text eol=lf 6 | -------------------------------------------------------------------------------- /.github/advanced-issue-labeler.yml: -------------------------------------------------------------------------------- 1 | policy: 2 | - template: [report-a-bug.yml] 3 | section: 4 | - id: [minecraftVersion] 5 | block-list: [other] 6 | label: 7 | - name: Minecraft 1.21.5 8 | keys: ['1.21.5'] 9 | - name: Minecraft 1.21.4 10 | keys: ['1.21.4'] 11 | - name: Minecraft 1.21.1 12 | keys: ['1.21.1 (LTS)'] 13 | - name: Minecraft 1.20.1 14 | keys: ['1.20.1 (LTS)'] 15 | - name: EOL 16 | keys: ['Other (specify below)'] 17 | - id: [modLoader] 18 | label: 19 | - name: NeoForge 20 | keys: ['NeoForge'] 21 | - name: Fabric 22 | keys: ['Fabric'] 23 | - name: 'Forge' 24 | keys: ['Forge'] -------------------------------------------------------------------------------- /.github/workflows/label-issues.yaml: -------------------------------------------------------------------------------- 1 | name: Label Issues 2 | on: 3 | issues: 4 | types: [ opened ] 5 | jobs: 6 | label-component: 7 | runs-on: ubuntu-latest 8 | permissions: 9 | contents: read 10 | issues: write 11 | strategy: 12 | matrix: 13 | template: [ report-a-bug.yml ] 14 | steps: 15 | - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 16 | 17 | - name: Parse issue form 18 | uses: TwelveIterations/github-issue-parser@main 19 | id: issue-parser 20 | with: 21 | template-path: https://raw.githubusercontent.com/TwelveIterationMods/.github/refs/heads/main/.github/ISSUE_TEMPLATE/${{ matrix.template }} 22 | 23 | - name: Set labels based on component field 24 | uses: redhat-plumbers-in-action/advanced-issue-labeler@d498805e5c7c0658e336948b3363480bcfd68da6 25 | with: 26 | issue-form: ${{ steps.issue-parser.outputs.jsonString }} 27 | template: ${{ matrix.template }} 28 | token: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/manage-labels.yaml: -------------------------------------------------------------------------------- 1 | name: manage-labels 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | dry: 6 | description: 'Dry run (no changes, log only)' 7 | required: false 8 | default: true 9 | type: boolean 10 | remove_missing: 11 | description: 'Remove labels not present in the source data' 12 | required: false 13 | default: false 14 | type: boolean 15 | jobs: 16 | manage-labels: 17 | permissions: 18 | contents: read 19 | issues: write 20 | runs-on: ubuntu-latest 21 | name: manage-labels 22 | steps: 23 | - uses: actions/checkout@v2 24 | - uses: TwelveIterations/manage-labels@main 25 | with: 26 | dry: ${{ inputs.dry }} 27 | remove_missing: ${{ inputs.remove_missing }} 28 | source: https://raw.githubusercontent.com/TwelveIterationMods/.github/refs/heads/main/labels.yaml 29 | env: 30 | GITHUB_TOKEN: ${{ github.token }} 31 | -------------------------------------------------------------------------------- /.github/workflows/publish-release.yml: -------------------------------------------------------------------------------- 1 | name: publish-release 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | forge: 6 | description: 'Forge' 7 | required: true 8 | type: boolean 9 | default: true 10 | fabric: 11 | description: 'Fabric' 12 | required: true 13 | type: boolean 14 | default: true 15 | neoforge: 16 | description: 'NeoForge' 17 | required: true 18 | type: boolean 19 | default: true 20 | 21 | jobs: 22 | create-release: 23 | runs-on: ubuntu-latest 24 | outputs: 25 | ref: v${{ steps.bump-version.outputs.version }} 26 | version: ${{ steps.bump-version.outputs.version }} 27 | build-matrix: ${{ steps.set-build-matrix.outputs.result }} 28 | publish-matrix: ${{ steps.set-publish-matrix.outputs.result }} 29 | steps: 30 | - name: Checkout repository 31 | uses: actions/checkout@v4 32 | - name: Extracting version from properties 33 | shell: bash 34 | run: echo "version=$(cat gradle.properties | grep -w "\bversion\s*=" | cut -d= -f2)" >> $GITHUB_OUTPUT 35 | id: extract-version 36 | - name: Bumping version 37 | uses: TwelveIterationMods/bump-version@v1 38 | with: 39 | version: ${{ steps.extract-version.outputs.version }} 40 | bump: patch 41 | id: bump-version 42 | - name: Updating version properties 43 | run: | 44 | sed -i "s/^\s*version\s*=.*/version = ${{ steps.bump-version.outputs.version }}/g" gradle.properties 45 | git config user.name "GitHub Actions" 46 | git config user.email "<>" 47 | git commit -am "Set version to ${{ steps.bump-version.outputs.version }}" 48 | git push origin ${BRANCH_NAME} 49 | git tag -a "v${{ steps.bump-version.outputs.version }}" -m "Release ${{ steps.bump-version.outputs.version }}" 50 | git push origin "v${{ steps.bump-version.outputs.version }}" 51 | shell: bash 52 | env: 53 | BRANCH_NAME: ${{ github.head_ref || github.ref_name }} 54 | - name: Preparing build matrix 55 | id: set-build-matrix 56 | uses: actions/github-script@v7 57 | with: 58 | script: | 59 | const fs = require('fs'); 60 | const settingsGradle = fs.readFileSync('settings.gradle', 'utf8'); 61 | const includePattern = /^(?!\s*\/\/)\s*include\s*\(\s*(['"]([^'"]+)['"](?:,\s*['"]([^'"]+)['"])*\s*)\)/gm; 62 | const includes = [...settingsGradle.matchAll(includePattern)].flatMap(match => match[0].match(/['"]([^'"]+)['"]/g).map(item => item.replace(/['"]/g, ''))); 63 | const includeFabric = includes.includes('fabric') && ${{inputs.fabric}}; 64 | const includeForge = includes.includes('forge') && ${{inputs.forge}}; 65 | const includeNeoForge = includes.includes('neoforge') && ${{inputs.neoforge}}; 66 | return { 67 | loader: [includeFabric ? 'fabric' : false, includeForge ? 'forge' : false, includeNeoForge ? 'neoforge' : false].filter(Boolean), 68 | } 69 | - name: Preparing publish matrix 70 | id: set-publish-matrix 71 | uses: actions/github-script@v7 72 | with: 73 | script: | 74 | const fs = require('fs'); 75 | const settingsGradle = fs.readFileSync('settings.gradle', 'utf8'); 76 | const includePattern = /^(?!\s*\/\/)\s*include\s*\(\s*(['"]([^'"]+)['"](?:,\s*['"]([^'"]+)['"])*\s*)\)/gm; 77 | const includes = [...settingsGradle.matchAll(includePattern)].flatMap(match => match[0].match(/['"]([^'"]+)['"]/g).map(item => item.replace(/['"]/g, ''))); 78 | const includeFabric = includes.includes('fabric') && ${{inputs.fabric}}; 79 | const includeForge = includes.includes('forge') && ${{inputs.forge}}; 80 | const includeNeoForge = includes.includes('neoforge') && ${{inputs.neoforge}}; 81 | const gradleProperties = fs.readFileSync('gradle.properties', 'utf8'); 82 | const curseForgeProjectId = gradleProperties.match(/^(?!#)curseforge_project_id\s*=\s*(.+)/m); 83 | const modrinthProjectId = gradleProperties.match(/^(?!#)modrinth_project_id\s*=\s*(.+)/m); 84 | const mavenReleases = gradleProperties.match(/^(?!#)maven_releases\s*=\s*(.+)/m); 85 | return { 86 | loader: ['common', includeFabric ? 'fabric' : false, includeForge ? 'forge' : false, includeNeoForge ? 'neoforge' : false].filter(Boolean), 87 | site: [curseForgeProjectId ? 'curseforge' : '', modrinthProjectId ? 'modrinth' : '', mavenReleases ? 'publish' : ''].filter(Boolean), 88 | exclude: [ 89 | {loader: 'common', site: 'curseforge'}, 90 | {loader: 'common', site: 'modrinth'} 91 | ] 92 | } 93 | build-common: 94 | runs-on: ubuntu-latest 95 | steps: 96 | - name: Checkout repository 97 | uses: actions/checkout@v4 98 | with: 99 | ref: ${{ needs.create-release.outputs.ref }} 100 | - name: Validate gradle wrapper 101 | uses: gradle/actions/wrapper-validation@v3 102 | - name: Setup JDK 103 | uses: actions/setup-java@v4 104 | with: 105 | java-version: 21 106 | distribution: temurin 107 | cache: 'gradle' 108 | - name: Make gradle wrapper executable 109 | run: chmod +x ./gradlew 110 | - name: Build common artifact 111 | run: ./gradlew :common:build '-Pversion=${{needs.create-release.outputs.version}}' 112 | - name: Upload common artifact 113 | uses: actions/upload-artifact@v4 114 | with: 115 | name: common-artifact 116 | path: common/build 117 | needs: create-release 118 | build-release: 119 | runs-on: ubuntu-latest 120 | strategy: 121 | matrix: ${{fromJson(needs.create-release.outputs.build-matrix)}} 122 | fail-fast: false 123 | steps: 124 | - name: Checkout repository 125 | uses: actions/checkout@v4 126 | with: 127 | ref: ${{ needs.create-release.outputs.ref }} 128 | - name: Validate gradle wrapper 129 | uses: gradle/actions/wrapper-validation@v3 130 | - name: Setup JDK 131 | uses: actions/setup-java@v4 132 | with: 133 | java-version: 21 134 | distribution: temurin 135 | cache: 'gradle' 136 | - name: Make gradle wrapper executable 137 | run: chmod +x ./gradlew 138 | - name: Download common artifact 139 | uses: actions/download-artifact@v4 140 | with: 141 | name: common-artifact 142 | path: common/build 143 | - name: Build ${{ matrix.loader }} artifact 144 | run: ./gradlew :${{ matrix.loader }}:build '-Pversion=${{needs.create-release.outputs.version}}' 145 | - name: Upload ${{ matrix.loader }} artifact 146 | uses: actions/upload-artifact@v4 147 | with: 148 | name: ${{ matrix.loader }}-artifact 149 | path: ${{ matrix.loader }}/build 150 | needs: 151 | - create-release 152 | - build-common 153 | publish-release: 154 | runs-on: ubuntu-latest 155 | strategy: 156 | matrix: ${{fromJson(needs.create-release.outputs.publish-matrix)}} 157 | fail-fast: false 158 | steps: 159 | - name: Checkout repository 160 | uses: actions/checkout@v4 161 | with: 162 | ref: ${{ needs.create-release.outputs.ref }} 163 | - name: Download ${{ matrix.loader }} artifact 164 | uses: actions/download-artifact@v4 165 | with: 166 | name: ${{ matrix.loader }}-artifact 167 | path: ${{ matrix.loader }}/build 168 | - name: Validate gradle wrapper 169 | uses: gradle/actions/wrapper-validation@v3 170 | - name: Setup JDK 171 | uses: actions/setup-java@v4 172 | with: 173 | java-version: 21 174 | distribution: temurin 175 | cache: 'gradle' 176 | - name: Make gradle wrapper executable 177 | run: chmod +x ./gradlew 178 | - name: Publish 179 | run: ./gradlew :${{ matrix.loader }}:${{ matrix.site }} '-Pversion=${{needs.create-release.outputs.version}}' '-PmavenUsername=${{ secrets.MAVEN_USER }}' '-PmavenPassword=${{ secrets.MAVEN_PASSWORD }}' 180 | env: 181 | CURSEFORGE_TOKEN: ${{secrets.CURSEFORGE_TOKEN}} 182 | MODRINTH_TOKEN: ${{secrets.MODRINTH_TOKEN}} 183 | needs: 184 | - create-release 185 | - build-common 186 | - build-release -------------------------------------------------------------------------------- /.github/workflows/publish-snapshot.yml: -------------------------------------------------------------------------------- 1 | name: publish-snapshot 2 | on: 3 | push: 4 | branches: 5 | - '**' 6 | 7 | jobs: 8 | prepare-matrix: 9 | runs-on: ubuntu-latest 10 | outputs: 11 | matrix: ${{ steps.set-matrix.outputs.result }} 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v4 15 | - name: Preparing matrix 16 | id: set-matrix 17 | uses: actions/github-script@v7 18 | with: 19 | script: | 20 | const fs = require('fs'); 21 | const settingsGradle = fs.readFileSync('settings.gradle', 'utf8'); 22 | const includePattern = /^(?!\s*\/\/)\s*include\s*\(\s*(['"]([^'"]+)['"](?:,\s*['"]([^'"]+)['"])*\s*)\)/gm; 23 | const includes = [...settingsGradle.matchAll(includePattern)] 24 | .flatMap(match => match[0].match(/['"]([^'"]+)['"]/g).map(item => item.replace(/['"]/g, ''))); 25 | const includeFabric = includes.includes('fabric'); 26 | const includeForge = includes.includes('forge'); 27 | const includeNeoForge = includes.includes('neoforge'); 28 | const gradleProperties = fs.readFileSync('gradle.properties', 'utf8'); 29 | const mavenSnapshots = gradleProperties.match(/^(?!#)maven_snapshots\s*=\s*(.+)/m); 30 | return { 31 | loader: ['common', includeFabric ? 'fabric' : false, includeForge ? 'forge' : false, includeNeoForge ? 'neoforge' : false].filter(Boolean), 32 | task: [mavenSnapshots ? 'publish' : 'build'] 33 | }; 34 | publish-snapshot: 35 | runs-on: ubuntu-latest 36 | strategy: 37 | matrix: ${{fromJson(needs.prepare-matrix.outputs.matrix)}} 38 | fail-fast: false 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v4 42 | - name: Validate gradle wrapper 43 | uses: gradle/actions/wrapper-validation@v3 44 | - name: Setup JDK 45 | uses: actions/setup-java@v4 46 | with: 47 | java-version: 21 48 | distribution: temurin 49 | - name: Make gradle wrapper executable 50 | run: chmod +x ./gradlew 51 | - name: Extracting version from properties 52 | shell: bash 53 | run: echo "version=$(cat gradle.properties | grep -w "\bversion\s*=" | cut -d= -f2)" >> $GITHUB_OUTPUT 54 | id: extract-version 55 | - name: Bumping version 56 | uses: TwelveIterationMods/bump-version@v1 57 | with: 58 | version: ${{ steps.extract-version.outputs.version }} 59 | bump: patch 60 | id: bump-version 61 | - name: Publish 62 | run: ./gradlew :${{ matrix.loader }}:${{ matrix.task }} '-Pversion=${{ steps.bump-version.outputs.version }}-SNAPSHOT' '-PmavenUsername=${{ secrets.MAVEN_USER }}' '-PmavenPassword=${{ secrets.MAVEN_PASSWORD }}' 63 | needs: prepare-matrix -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # eclipse 2 | bin 3 | *.launch 4 | .eclipse 5 | .settings 6 | .metadata 7 | .classpath 8 | .project 9 | 10 | # idea 11 | out 12 | *.ipr 13 | *.iws 14 | *.iml 15 | .idea 16 | 17 | # gradle 18 | build 19 | .gradle 20 | 21 | # other 22 | eclipse 23 | run 24 | runs 25 | runserver 26 | logs 27 | 28 | common/src/generated/resources/.cache -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | - Fixed client-side blindness effect being sometimes applied during world join on Forge/NeoForge -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | All Rights Reserved 2 | 3 | Copyright (c) 2023 BlayTheNinth 4 | 5 | For modpack permissions and other exceptions, see https://mods.twelveiterations.com/permissions 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 8 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 9 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 10 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Forgiving Void 2 | 3 | Minecraft Mod. Makes the void hate you a little less (and vice-versa). Fall down and come back out on top. 4 | 5 | - [Modpack Permissions](https://mods.twelveiterations.com/permissions) 6 | 7 | #### Downloads 8 | 9 | [![Versions](http://cf.way2muchnoise.eu/versions/271009_latest.svg)](https://minecraft.curseforge.com/projects/forgiving-void) [![Downloads](http://cf.way2muchnoise.eu/full_271009_downloads.svg)](https://minecraft.curseforge.com/projects/forgiving-void) 10 | 11 | ## Contributing 12 | 13 | If you're interested in contributing to the mod, you can check out [issues labelled as "help wanted"](https://github.com/TwelveIterationMods/ForgivingVoid/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22). 14 | 15 | When it comes to new features, it's best to confer with me first to ensure we share the same vision. You can join us on [Discord](https://discord.gg/VAfZ2Nau6j) if you'd like to talk. 16 | 17 | Contributions must be done through pull requests. I will not be able to accept translations, code or other assets through any other channels. 18 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'fabric-loom' version '1.10-SNAPSHOT' apply(false) 3 | id 'net.neoforged.moddev' version '2.0.78' apply(false) 4 | id 'net.darkhax.curseforgegradle' version '1.1.26' apply(false) 5 | id "com.modrinth.minotaur" version "2.+" apply(false) 6 | } 7 | 8 | subprojects { 9 | configurations.all { 10 | resolutionStrategy { 11 | cacheChangingModulesFor 60, 'seconds' 12 | cacheDynamicVersionsFor 60, 'seconds' 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /buildSrc/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'groovy-gradle-plugin' 3 | } -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/multiloader-common.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java-library' 3 | id 'maven-publish' 4 | } 5 | 6 | base { 7 | archivesName = "${mod_id}-${project.name}-${minecraft_version}" 8 | version = project.version 9 | } 10 | 11 | java { 12 | toolchain.languageVersion = JavaLanguageVersion.of(java_version) 13 | withSourcesJar() 14 | withJavadocJar() 15 | } 16 | 17 | repositories { 18 | mavenCentral() 19 | // https://docs.gradle.org/current/userguide/declaring_repositories.html#declaring_content_exclusively_found_in_one_repository 20 | exclusiveContent { 21 | forRepository { 22 | maven { 23 | name = 'Sponge' 24 | url = 'https://repo.spongepowered.org/repository/maven-public' 25 | } 26 | } 27 | filter { includeGroupAndSubgroups("org.spongepowered") } 28 | } 29 | maven { 30 | url "https://maven.twelveiterations.com/repository/maven-public/" 31 | content { 32 | includeGroup "net.blay09.mods" 33 | } 34 | } 35 | exclusiveContent { 36 | forRepositories( 37 | maven { 38 | name = 'ParchmentMC' 39 | url = 'https://maven.parchmentmc.org/' 40 | }, 41 | maven { 42 | name = "NeoForge" 43 | url = 'https://maven.neoforged.net/releases' 44 | } 45 | ) 46 | filter { includeGroup('org.parchmentmc.data') } 47 | } 48 | } 49 | 50 | dependencies { 51 | implementation 'org.jetbrains:annotations:24.1.0' 52 | } 53 | 54 | // Declare capabilities on the outgoing configurations. 55 | // Read more about capabilities here: https://docs.gradle.org/current/userguide/component_capabilities.html#sec:declaring-additional-capabilities-for-a-local-component 56 | ['apiElements', 'runtimeElements', 'sourcesElements', 'javadocElements'].each { variant -> 57 | configurations."$variant".outgoing { 58 | capability("$group:${mod_id.replace('_', '-')}-${project.name}:$version") 59 | capability("$group:${mod_id.replace('_', '-')}:$version") 60 | } 61 | publishing.publications.configureEach { 62 | suppressPomMetadataWarningsFor(variant) 63 | } 64 | } 65 | 66 | sourcesJar { 67 | from(rootProject.file("LICENSE")) { 68 | rename { "${it}_${mod_name}" } 69 | } 70 | } 71 | 72 | jar { 73 | from(rootProject.file("LICENSE")) { 74 | rename { "${it}_${mod_name}" } 75 | } 76 | 77 | manifest { 78 | attributes([ 79 | 'Specification-Title' : mod_name, 80 | 'Specification-Vendor' : mod_author, 81 | 'Specification-Version' : project.jar.archiveVersion, 82 | 'Implementation-Title' : project.name, 83 | 'Implementation-Version': project.jar.archiveVersion, 84 | 'Implementation-Vendor' : mod_author, 85 | 'Built-On-Minecraft' : minecraft_version, 86 | 'MixinConfigs' : "${mod_id}.mixins.json,${mod_id}.${project.name}.mixins.json", 87 | ]) 88 | } 89 | } 90 | 91 | processResources { 92 | def expandProps = [ 93 | "version": version, 94 | "group": project.group, //Else we target the task's group. 95 | "minecraft_version": minecraft_version, 96 | "minimum_minecraft_version": minecraft_version_range.replaceAll("[\\[\\])]", "").split(",")[0], 97 | "forge_version": forge_version, 98 | "forge_loader_version_range": forge_loader_version_range, 99 | "forge_version_range": forge_version_range, 100 | "minecraft_version_range": minecraft_version_range, 101 | "fabric_version": fabric_version, 102 | "fabric_loader_version": fabric_loader_version, 103 | "mod_name": mod_name, 104 | "mod_main": mod_name.replaceAll(" ", ""), 105 | "mod_author": mod_author, 106 | "mod_id": mod_id, 107 | "license": license, 108 | "description": project.description, 109 | "neoforge_version": neoforge_version, 110 | "neoforge_version_range": neoforge_version_range, 111 | "neoforge_loader_version_range": neoforge_loader_version_range, 112 | "credits": credits, 113 | "java_version": java_version, 114 | "homepage": homepage, 115 | "discord": discord, 116 | "issues": issues, 117 | "sources": sources, 118 | "pack_format_number": pack_format_number, 119 | "balm_version_range": balm_version_range, 120 | "minimum_balm_version": balm_version_range.replaceAll("[\\[\\])]", "").split(",")[0], 121 | ] 122 | 123 | filesMatching(['pack.mcmeta', 'fabric.mod.json', 'META-INF/mods.toml', 'META-INF/neoforge.mods.toml', '*.mixins.json']) { 124 | expand expandProps 125 | } 126 | inputs.properties(expandProps) 127 | } 128 | 129 | publishing { 130 | publications { 131 | register('mavenJava', MavenPublication) { 132 | version = project.version + (!project.version.endsWith("SNAPSHOT") ? "+" + minecraft_version : "") 133 | artifactId "${mod_id.replace('_', '-')}-${project.name}" 134 | from components.java 135 | } 136 | } 137 | repositories { 138 | def repoUrl = version.toString().endsWith("SNAPSHOT") ? findProperty("maven_snapshots") : findProperty("maven_releases") 139 | if (repoUrl != null) { 140 | maven { 141 | url = uri(repoUrl) 142 | name = "maven" 143 | credentials(PasswordCredentials) 144 | } 145 | } 146 | } 147 | } -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/multiloader-loader.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'multiloader-common' 3 | } 4 | 5 | configurations { 6 | commonJava { 7 | canBeResolved = true 8 | } 9 | commonResources { 10 | canBeResolved = true 11 | } 12 | commonGeneratedResources { 13 | canBeResolved = true 14 | } 15 | } 16 | 17 | dependencies { 18 | compileOnly(project(':common')) { 19 | capabilities { 20 | requireCapability "$group:${mod_id.replace('_', '-')}" 21 | } 22 | } 23 | commonJava project(path: ':common', configuration: 'commonJava') 24 | commonResources project(path: ':common', configuration: 'commonResources') 25 | commonGeneratedResources project(path: ':common', configuration: 'commonGeneratedResources') 26 | } 27 | 28 | tasks.named('compileJava', JavaCompile) { 29 | dependsOn(configurations.commonJava) 30 | source(configurations.commonJava) 31 | } 32 | 33 | processResources { 34 | dependsOn(configurations.commonResources) 35 | dependsOn(configurations.commonGeneratedResources) 36 | from(configurations.commonResources) 37 | from(configurations.commonGeneratedResources) 38 | } 39 | 40 | tasks.named('javadoc', Javadoc).configure { 41 | dependsOn(configurations.commonJava) 42 | source(configurations.commonJava) 43 | } 44 | 45 | tasks.named("sourcesJar", Jar) { 46 | dependsOn(configurations.commonJava) 47 | from(configurations.commonJava) 48 | dependsOn(configurations.commonResources) 49 | from(configurations.commonResources) 50 | dependsOn(configurations.commonGeneratedResources) 51 | from(configurations.commonGeneratedResources) 52 | } -------------------------------------------------------------------------------- /common/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'multiloader-common' 3 | id 'net.neoforged.moddev' 4 | } 5 | 6 | base { 7 | archivesName = "${mod_id}-common-${minecraft_version}" 8 | } 9 | 10 | neoForge { 11 | neoFormVersion = neo_form_version 12 | // Automatically enable AccessTransformers if the file exists 13 | def at = file('src/main/resources/META-INF/accesstransformer.cfg') 14 | if (at.exists()) { 15 | accessTransformers.from(at.absolutePath) 16 | } 17 | parchment { 18 | minecraftVersion = parchment_minecraft 19 | mappingsVersion = parchment_version 20 | } 21 | } 22 | 23 | dependencies { 24 | compileOnly "org.spongepowered:mixin:$mixin_version" 25 | } 26 | 27 | apply from: rootProject.file('repositories.gradle') 28 | apply from: 'dependencies.gradle' 29 | 30 | configurations { 31 | commonJava { 32 | canBeResolved = false 33 | canBeConsumed = true 34 | } 35 | commonResources { 36 | canBeResolved = false 37 | canBeConsumed = true 38 | } 39 | commonGeneratedResources { 40 | canBeResolved = false 41 | canBeConsumed = true 42 | } 43 | } 44 | 45 | sourceSets { 46 | generated { 47 | resources { 48 | srcDir 'src/generated/resources' 49 | } 50 | } 51 | } 52 | 53 | artifacts { 54 | commonJava sourceSets.main.java.sourceDirectories.singleFile 55 | commonResources sourceSets.main.resources.sourceDirectories.singleFile 56 | commonGeneratedResources sourceSets.generated.resources.sourceDirectories.singleFile 57 | } 58 | 59 | sourceSets { 60 | main { 61 | java { 62 | srcDir 'src/shell/java' 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /common/dependencies.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | implementation("net.blay09.mods:balm-common:${balm_version}") { 3 | changing = balm_version.endsWith("SNAPSHOT") 4 | } 5 | } -------------------------------------------------------------------------------- /common/src/main/java/net/blay09/mods/forgivingvoid/DamageOnFallMode.java: -------------------------------------------------------------------------------- 1 | package net.blay09.mods.forgivingvoid; 2 | 3 | import net.minecraft.util.StringRepresentable; 4 | 5 | import java.util.Locale; 6 | 7 | public enum DamageOnFallMode implements StringRepresentable { 8 | ABSOLUTE, 9 | RELATIVE_CURRENT, 10 | RELATIVE_MAX; 11 | 12 | @Override 13 | public String getSerializedName() { 14 | return name().toLowerCase(Locale.ROOT); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /common/src/main/java/net/blay09/mods/forgivingvoid/ForgivingVoid.java: -------------------------------------------------------------------------------- 1 | package net.blay09.mods.forgivingvoid; 2 | 3 | import net.blay09.mods.balm.api.Balm; 4 | import net.blay09.mods.balm.api.event.LivingFallEvent; 5 | import net.blay09.mods.balm.api.event.TickPhase; 6 | import net.blay09.mods.balm.api.event.TickType; 7 | import net.blay09.mods.forgivingvoid.mixin.ServerGamePacketListenerImplAccessor; 8 | import net.blay09.mods.forgivingvoid.mixin.ServerPlayerAccessor; 9 | import net.blay09.mods.forgivingvoid.mixin.ThrownTridentAccessor; 10 | import net.minecraft.core.BlockPos; 11 | import net.minecraft.core.registries.BuiltInRegistries; 12 | import net.minecraft.nbt.CompoundTag; 13 | import net.minecraft.resources.ResourceKey; 14 | import net.minecraft.resources.ResourceLocation; 15 | import net.minecraft.server.level.ServerPlayer; 16 | import net.minecraft.world.effect.MobEffectInstance; 17 | import net.minecraft.world.entity.Entity; 18 | import net.minecraft.world.entity.LivingEntity; 19 | import net.minecraft.world.entity.player.Player; 20 | import net.minecraft.world.entity.projectile.ThrownTrident; 21 | import net.minecraft.world.level.Level; 22 | import net.minecraft.world.level.block.Block; 23 | import net.minecraft.world.level.block.Blocks; 24 | import org.jetbrains.annotations.Nullable; 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | 28 | import java.util.ArrayList; 29 | import java.util.Set; 30 | 31 | public class ForgivingVoid { 32 | 33 | public static final String MOD_ID = "forgivingvoid"; 34 | 35 | public static final Logger logger = LoggerFactory.getLogger(ForgivingVoid.class); 36 | 37 | public static void initialize() { 38 | ForgivingVoidConfig.initialize(); 39 | 40 | Balm.getEvents().onTickEvent(TickType.Entity, TickPhase.Start, ForgivingVoid::onEntityTick); 41 | Balm.getEvents().onEvent(LivingFallEvent.class, ForgivingVoid::onLivingEntityFall); 42 | } 43 | 44 | public static void onEntityTick(Entity entity) { 45 | if (!isAllowedEntity(entity)) { 46 | return; 47 | } 48 | 49 | int triggerAtY = entity.level().getMinY() - ForgivingVoidConfig.getActive().triggerAtDistanceBelow; 50 | boolean isInVoid = entity.getY() < triggerAtY && entity.yo < triggerAtY; 51 | boolean isTeleporting = entity instanceof ServerPlayer player && ((ServerGamePacketListenerImplAccessor) player.connection).getAwaitingPositionFromClient() != null; 52 | CompoundTag persistentData = Balm.getHooks().getPersistentData(entity); 53 | if (entity.onGround()) { 54 | persistentData.putLong("LastGroundedPos", entity.blockPosition().asLong()); 55 | } 56 | 57 | if (isInVoid && !isTeleporting && isEnabledForDimension(entity.level().dimension()) && fireForgivingVoidEvent(entity)) { 58 | if (entity instanceof LivingEntity livingEntity) { 59 | applyFallThroughVoidEffects(livingEntity); 60 | } 61 | 62 | final var entitiesToTeleport = new ArrayList(); 63 | entitiesToTeleport.add(entity); 64 | if (entity.isVehicle()) { 65 | entitiesToTeleport.addAll(entity.getPassengers()); 66 | entity.ejectPassengers(); 67 | } 68 | 69 | final var vehicle = entity.getVehicle(); 70 | if (vehicle != null) { 71 | entitiesToTeleport.add(vehicle); 72 | entity.stopRiding(); 73 | } 74 | 75 | entitiesToTeleport.forEach(teleportedEntity -> { 76 | if (isAllowedEntity(teleportedEntity)) { 77 | if (teleportedEntity instanceof ServerPlayerAccessor player) { 78 | player.setIsChangingDimension(true); 79 | } 80 | final var teleportedEntityData = Balm.getHooks().getPersistentData(teleportedEntity); 81 | final var returnToGrounded = ForgivingVoidConfig.getActive().returnToLastGrounded; 82 | final var lastGroundedPos = teleportedEntityData.getLong("LastGroundedPos").map(BlockPos::of).orElseGet(teleportedEntity::blockPosition); 83 | final var x = returnToGrounded ? lastGroundedPos.getX() + 0.5f : teleportedEntity.getX(); 84 | final var y = ForgivingVoidConfig.getActive().fallingHeight; 85 | final var z = returnToGrounded ? lastGroundedPos.getZ() + 0.5f : teleportedEntity.getZ(); 86 | teleportedEntity.teleportTo(x, y, z); 87 | teleportedEntityData.putBoolean("ForgivingVoidIsFalling", true); 88 | } 89 | }); 90 | 91 | if (vehicle != null) { 92 | entity.startRiding(vehicle); 93 | } 94 | } else if (persistentData.getBooleanOr("ForgivingVoidIsFalling", false)) { 95 | // LivingFallEvent is not called when the player falls into water or is flying, so reset it manually - and give no damage at all. 96 | if (hasLanded(entity) || isOrMayFly(entity)) { 97 | persistentData.putBoolean("ForgivingVoidIsFalling", false); 98 | if (entity instanceof ServerPlayerAccessor player) { 99 | player.setIsChangingDimension(false); 100 | } 101 | return; 102 | } 103 | 104 | if (ForgivingVoidConfig.getActive().disableVanillaAntiCheatWhileFalling && entity instanceof ServerPlayerAccessor player) { 105 | // Vanilla's AntiCheat is triggers on falling and teleports, even in Vanilla. 106 | // So I'll just disable it until the player lands, so it doesn't look like it's my mod causing the issue. 107 | player.setIsChangingDimension(true); 108 | } 109 | } 110 | } 111 | 112 | private static void applyFallThroughVoidEffects(LivingEntity entity) { 113 | for (String effectString : ForgivingVoidConfig.getActive().fallThroughVoidEffects) { 114 | String[] parts = effectString.split("\\|"); 115 | ResourceLocation registryName = ResourceLocation.tryParse(parts[0]); 116 | if (registryName != null) { 117 | final var holder = BuiltInRegistries.MOB_EFFECT.get(registryName); 118 | if (holder.isPresent()) { 119 | int duration = tryParseInt(parts.length >= 2 ? parts[1] : null, 600); 120 | int amplifier = tryParseInt(parts.length >= 3 ? parts[2] : null, 0); 121 | entity.addEffect(new MobEffectInstance(holder.get(), duration, amplifier)); 122 | } else { 123 | ForgivingVoid.logger.info("Invalid fall through void effect '{}'", parts[0]); 124 | } 125 | } else { 126 | ForgivingVoid.logger.info("Invalid fall through void effect '{}'", parts[0]); 127 | } 128 | } 129 | } 130 | 131 | private static int tryParseInt(@Nullable String text, int defaultVal) { 132 | if (text != null) { 133 | try { 134 | return Integer.parseInt(text); 135 | } catch (NumberFormatException e) { 136 | return defaultVal; 137 | } 138 | } 139 | return defaultVal; 140 | } 141 | 142 | private static boolean isAllowedEntity(Entity entity) { 143 | if (entity.level().isClientSide) { 144 | return false; 145 | } 146 | 147 | final var entityAllowList = ForgivingVoidConfig.getActive().entityAllowList; 148 | final var entityId = BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()); 149 | if (entityAllowList.isEmpty() && entity instanceof Player) { 150 | return true; 151 | } 152 | 153 | if (ForgivingVoidConfig.getActive().tridentForgiveness && entity instanceof ThrownTrident trident) { 154 | final var loyalty = trident.getEntityData().get(ThrownTridentAccessor.getIdLoyalty()); 155 | //noinspection UnreachableCode 156 | if (loyalty > 0) { 157 | return true; 158 | } 159 | } 160 | 161 | return entityAllowList.contains(entityId); 162 | } 163 | 164 | public static final Set FALL_CATCHING_BLOCKS = Set.of(Blocks.COBWEB); 165 | 166 | private static boolean hasLanded(Entity entity) { 167 | if (entity.onGround() || entity.isInWater() || entity.isInLava()) { 168 | return true; 169 | } 170 | 171 | final var landedOnState = entity.level().getBlockState(entity.blockPosition()); 172 | return FALL_CATCHING_BLOCKS.contains(landedOnState.getBlock()); 173 | } 174 | 175 | private static boolean isOrMayFly(Entity entity) { 176 | if (!(entity instanceof Player player)) { 177 | return false; 178 | } 179 | 180 | return player.getAbilities().flying || player.getAbilities().mayfly; 181 | } 182 | 183 | public static void onLivingEntityFall(LivingFallEvent event) { 184 | LivingEntity entity = event.getEntity(); 185 | if (isAllowedEntity(entity)) { 186 | CompoundTag persistentData = Balm.getHooks().getPersistentData(entity); 187 | if (persistentData.getBooleanOr("ForgivingVoidIsFalling", false)) { 188 | final var config = ForgivingVoidConfig.getActive(); 189 | final var damage = calculateFallDamage(config, entity); 190 | event.setFallDamageOverride(damage); 191 | 192 | if (entity instanceof ServerPlayerAccessor player) { 193 | player.setIsChangingDimension(false); 194 | } 195 | } 196 | } 197 | } 198 | 199 | private static float calculateFallDamage(ForgivingVoidConfig config, LivingEntity entity) { 200 | float damage = config.damageOnFall; 201 | // We normalize percentages if the user accidentally set a value out of 100. 202 | if (config.damageOnFallMode != DamageOnFallMode.ABSOLUTE && damage > 1) { 203 | damage = damage / 100f; 204 | } 205 | if (config.damageOnFallMode == DamageOnFallMode.RELATIVE_CURRENT) { 206 | damage = entity.getHealth() * damage; 207 | } else if (config.damageOnFallMode == DamageOnFallMode.RELATIVE_MAX) { 208 | damage = entity.getMaxHealth() * damage; 209 | } 210 | if (config.preventDeath && entity.getHealth() - damage <= 0) { 211 | damage = entity.getHealth() - 1f; 212 | } 213 | return damage; 214 | } 215 | 216 | private static boolean fireForgivingVoidEvent(Entity entity) { 217 | ForgivingVoidFallThroughEvent event = new ForgivingVoidFallThroughEvent(entity); 218 | Balm.getEvents().fireEvent(event); 219 | return !event.isCanceled(); 220 | } 221 | 222 | private static boolean isEnabledForDimension(ResourceKey dimensionKey) { 223 | if (dimensionKey == Level.OVERWORLD) { 224 | return ForgivingVoidConfig.getActive().triggerInOverworld; 225 | } else if (dimensionKey == Level.END) { 226 | return ForgivingVoidConfig.getActive().triggerInEnd; 227 | } else if (dimensionKey == Level.NETHER) { 228 | return ForgivingVoidConfig.getActive().triggerInNether; 229 | } else { 230 | final ResourceLocation dimension = dimensionKey.location(); 231 | final var dimensionAllowList = ForgivingVoidConfig.getActive().dimensionAllowList; 232 | final var dimensionDenyList = ForgivingVoidConfig.getActive().dimensionDenyList; 233 | if (!dimensionAllowList.isEmpty() && !dimensionAllowList.contains(dimension)) { 234 | return false; 235 | } else { 236 | return !dimensionDenyList.contains(dimension); 237 | } 238 | } 239 | } 240 | 241 | } 242 | -------------------------------------------------------------------------------- /common/src/main/java/net/blay09/mods/forgivingvoid/ForgivingVoidConfig.java: -------------------------------------------------------------------------------- 1 | package net.blay09.mods.forgivingvoid; 2 | 3 | import net.blay09.mods.balm.api.Balm; 4 | import net.blay09.mods.balm.api.config.reflection.Comment; 5 | import net.blay09.mods.balm.api.config.reflection.Config; 6 | import net.blay09.mods.balm.api.config.reflection.NestedType; 7 | import net.minecraft.resources.ResourceLocation; 8 | 9 | import java.util.HashSet; 10 | import java.util.List; 11 | import java.util.Set; 12 | 13 | @Config(ForgivingVoid.MOD_ID) 14 | public class ForgivingVoidConfig { 15 | 16 | @Comment("The distance to the minimum y level at which Forgiving Void should forgive the player and send them towards the sky.") 17 | public int triggerAtDistanceBelow = 32; 18 | 19 | @Comment("Set to ABSOLUTE for absolute fall damage in half hearts, RELATIVE_CURRENT for a percentage of their current health, or RELATIVE_MAX for a percentage of their max health.") 20 | public DamageOnFallMode damageOnFallMode = DamageOnFallMode.ABSOLUTE; 21 | 22 | @Comment("The amount of damage applied to the player when they land.") 23 | public float damageOnFall = 19; 24 | 25 | @Comment("The height from which the player will be falling after falling through the void.") 26 | public int fallingHeight = 300; 27 | 28 | @Comment("Set to true to make Forgiving Void return the player to the sky above their last grounded position instead of their current position. Prevents players from using Forgiving Void to fly across larger distances.") 29 | public boolean returnToLastGrounded = true; 30 | 31 | @Comment("Prevent death on void fall (limits damage to leave at least 0.5 hearts)") 32 | public boolean preventDeath = false; 33 | 34 | @Comment("Set to false to make Forgiving Void not trigger in the overworld void (dimension 0).") 35 | public boolean triggerInOverworld = true; 36 | 37 | @Comment("Set to false to make Forgiving Void not trigger in the nether void (dimension -1).") 38 | public boolean triggerInNether = true; 39 | 40 | @Comment("Set to false to make Forgiving Void not trigger in the end void (dimension 1).") 41 | public boolean triggerInEnd = true; 42 | 43 | @Comment("Set to true if players are rubber-banding while falling through the void. If you're hosting a public server, you should only do this if you have proper anti-cheat installed.") 44 | public boolean disableVanillaAntiCheatWhileFalling = true; 45 | 46 | @Comment("Set to true to have tridents with loyalty be affected by Forgiving Void. Not supported on Forge.") 47 | public boolean tridentForgiveness = false; 48 | 49 | @NestedType(String.class) 50 | @Comment("Effects applied to a player when they fall through the void, in the format \"effect|duration|amplifier\"") 51 | public List fallThroughVoidEffects = List.of("minecraft:blindness|60|3"); 52 | 53 | @Comment("List of dimension ids to be allowed for Forgiving Void. Options triggerInOverworld etc. take priority.") 54 | @NestedType(ResourceLocation.class) 55 | public Set dimensionAllowList = new HashSet<>(); 56 | 57 | @Comment("List of additional dimension ids to be deny-listed from Forgiving Void. Options triggerInOverworld etc. take priority. Ignored if dimensionAllowList is set.") 58 | @NestedType(ResourceLocation.class) 59 | public Set dimensionDenyList = new HashSet<>(); 60 | 61 | @Comment("List of entity ids to be allowed for Forgiving Void. On Forge this only supports living entities.") 62 | @NestedType(ResourceLocation.class) 63 | public Set entityAllowList = Set.of(ResourceLocation.withDefaultNamespace("player")); 64 | 65 | public static ForgivingVoidConfig getActive() { 66 | return Balm.getConfig().getActiveConfig(ForgivingVoidConfig.class); 67 | } 68 | 69 | public static void initialize() { 70 | Balm.getConfig().registerConfig(ForgivingVoidConfig.class); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /common/src/main/java/net/blay09/mods/forgivingvoid/ForgivingVoidFallThroughEvent.java: -------------------------------------------------------------------------------- 1 | package net.blay09.mods.forgivingvoid; 2 | 3 | import net.blay09.mods.balm.api.event.BalmEvent; 4 | import net.minecraft.world.entity.Entity; 5 | 6 | public class ForgivingVoidFallThroughEvent extends BalmEvent { 7 | 8 | private final Entity entity; 9 | 10 | public ForgivingVoidFallThroughEvent(Entity entity) { 11 | this.entity = entity; 12 | } 13 | 14 | public Entity getEntity() { 15 | return entity; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/java/net/blay09/mods/forgivingvoid/mixin/CombatTrackerMixin.java: -------------------------------------------------------------------------------- 1 | package net.blay09.mods.forgivingvoid.mixin; 2 | 3 | import net.blay09.mods.balm.api.Balm; 4 | import net.minecraft.network.chat.Component; 5 | import net.minecraft.world.damagesource.CombatEntry; 6 | import net.minecraft.world.damagesource.CombatTracker; 7 | import net.minecraft.world.entity.Entity; 8 | import net.minecraft.world.entity.LivingEntity; 9 | import org.jetbrains.annotations.Nullable; 10 | import org.spongepowered.asm.mixin.Final; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.Shadow; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 16 | 17 | @Mixin(CombatTracker.class) 18 | public class CombatTrackerMixin { 19 | 20 | @Shadow 21 | @Final 22 | private LivingEntity mob; 23 | 24 | @Inject(method = "getFallMessage(Lnet/minecraft/world/damagesource/CombatEntry;Lnet/minecraft/world/entity/Entity;)Lnet/minecraft/network/chat/Component;", at = @At("HEAD"), cancellable = true) 25 | public void getFallMessage(CombatEntry combatEntry, @Nullable Entity entity, CallbackInfoReturnable callbackInfoReturnable) { 26 | final var persistentData = Balm.getHooks().getPersistentData(mob); 27 | if (persistentData.getBooleanOr("ForgivingVoidIsFalling", false)) { 28 | callbackInfoReturnable.setReturnValue(Component.translatable("death.fell.forgivingvoid", mob.getDisplayName())); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /common/src/main/java/net/blay09/mods/forgivingvoid/mixin/ServerGamePacketListenerImplAccessor.java: -------------------------------------------------------------------------------- 1 | package net.blay09.mods.forgivingvoid.mixin; 2 | 3 | import net.minecraft.server.network.ServerGamePacketListenerImpl; 4 | import net.minecraft.world.phys.Vec3; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(ServerGamePacketListenerImpl.class) 9 | public interface ServerGamePacketListenerImplAccessor { 10 | @Accessor 11 | Vec3 getAwaitingPositionFromClient(); 12 | } 13 | -------------------------------------------------------------------------------- /common/src/main/java/net/blay09/mods/forgivingvoid/mixin/ServerPlayerAccessor.java: -------------------------------------------------------------------------------- 1 | package net.blay09.mods.forgivingvoid.mixin; 2 | 3 | import net.minecraft.server.level.ServerPlayer; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.gen.Accessor; 6 | 7 | @Mixin(ServerPlayer.class) 8 | public interface ServerPlayerAccessor { 9 | 10 | @Accessor 11 | void setIsChangingDimension(boolean isChangingDimension); 12 | } 13 | -------------------------------------------------------------------------------- /common/src/main/java/net/blay09/mods/forgivingvoid/mixin/ThrownTridentAccessor.java: -------------------------------------------------------------------------------- 1 | package net.blay09.mods.forgivingvoid.mixin; 2 | 3 | import net.minecraft.network.syncher.EntityDataAccessor; 4 | import net.minecraft.world.entity.projectile.ThrownTrident; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | @Mixin(ThrownTrident.class) 9 | public interface ThrownTridentAccessor { 10 | 11 | @Accessor("ID_LOYALTY") 12 | static EntityDataAccessor getIdLoyalty() { 13 | throw new AssertionError(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /common/src/main/resources/assets/forgivingvoid/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "death.fell.forgivingvoid": "%1$s fell from the top of the world", 3 | "forgivingvoid.configuration.title": "Forgiving Void", 4 | "forgivingvoid.configuration.triggerAtDistanceBelow": "Trigger at Distance Below", 5 | "forgivingvoid.configuration.triggerAtDistanceBelow.tooltip": "The distance to the minimum y level at which Forgiving Void should forgive the player and send them towards the sky.", 6 | "forgivingvoid.configuration.damageOnFall": "Damage on Fall", 7 | "forgivingvoid.configuration.damageOnFall.tooltip": "The amount of damage applied to the player when they land.", 8 | "forgivingvoid.configuration.fallingHeight": "Falling Height", 9 | "forgivingvoid.configuration.fallingHeight.tooltip": "The height from which the player will be falling after falling through the void.", 10 | "forgivingvoid.configuration.preventDeath": "Prevent Death", 11 | "forgivingvoid.configuration.preventDeath.tooltip": "Prevent death on void fall (limits damage to leave at least 0.5 hearts)", 12 | "forgivingvoid.configuration.triggerInOverworld": "Trigger in Overworld", 13 | "forgivingvoid.configuration.triggerInOverworld.tooltip": "Set to false to make Forgiving Void not trigger in the overworld void (dimension 0).", 14 | "forgivingvoid.configuration.triggerInNether": "Trigger in Nether", 15 | "forgivingvoid.configuration.triggerInNether.tooltip": "Set to false to make Forgiving Void not trigger in the nether void (dimension -1).", 16 | "forgivingvoid.configuration.triggerInEnd": "Trigger in End", 17 | "forgivingvoid.configuration.triggerInEnd.tooltip": "Set to false to make Forgiving Void not trigger in the end void (dimension 1).", 18 | "forgivingvoid.configuration.disableVanillaAntiCheatWhileFalling": "Disable Vanilla AntiCheat While Falling", 19 | "forgivingvoid.configuration.disableVanillaAntiCheatWhileFalling.tooltip": "Set to true if players are rubber-banding while falling through the void. If you're hosting a public server, you should only do this if you have proper anti-cheat installed.", 20 | "forgivingvoid.configuration.dimensionAllowList": "Dimension Allow List", 21 | "forgivingvoid.configuration.dimensionAllowList.tooltip": "List of dimension ids to be allowed for Forgiving Void. Options triggerInOverworld etc. take priority.", 22 | "forgivingvoid.configuration.dimensionDenyList": "Dimension Deny List", 23 | "forgivingvoid.configuration.dimensionDenyList.tooltip": "List of additional dimension ids to be deny-listed from Forgiving Void. Options triggerInOverworld etc. take priority. Ignored if dimensionAllowList is set." 24 | } -------------------------------------------------------------------------------- /common/src/main/resources/assets/forgivingvoid/lang/es_es.json: -------------------------------------------------------------------------------- 1 | { 2 | "forgivingvoid.configuration.title": "Vacío piadoso", 3 | "forgivingvoid.configuration.triggerAtY": "Activar en Y", 4 | "forgivingvoid.configuration.damageOnFall": "Daño al caer", 5 | "forgivingvoid.configuration.fallingHeight": "Altura de caída", 6 | "forgivingvoid.configuration.preventDeath": "Prevenir muerte", 7 | "forgivingvoid.configuration.triggerInOverworld": "Activar en la superficie", 8 | "forgivingvoid.configuration.triggerInNether": "Activar en el Nether", 9 | "forgivingvoid.configuration.triggerInEnd": "Activar en el End", 10 | "forgivingvoid.configuration.disableVanillaAntiCheatWhileFalling": "Desactivar el antitrampa predeterminado al caer", 11 | "forgivingvoid.configuration.dimensionAllowList": "Lista de dimensiones permitidas", 12 | "forgivingvoid.configuration.dimensionDenyList": "Lista de dimensiones denegadas" 13 | } 14 | -------------------------------------------------------------------------------- /common/src/main/resources/assets/forgivingvoid/lang/ko_kr.json: -------------------------------------------------------------------------------- 1 | { 2 | "forgivingvoid.configuration.title": "너그러운 빈 공간", 3 | "forgivingvoid.configuration.triggerAtY": "Y에서 트리거", 4 | "forgivingvoid.configuration.damageOnFall": "추락 피해", 5 | "forgivingvoid.configuration.fallingHeight": "낙하 높이", 6 | "forgivingvoid.configuration.preventDeath": "사망 방지", 7 | "forgivingvoid.configuration.triggerInOverworld": "오버월드에서 트리거", 8 | "forgivingvoid.configuration.triggerInNether": "네더에서 트리거", 9 | "forgivingvoid.configuration.triggerInEnd": "엔드에서 트리거", 10 | "forgivingvoid.configuration.disableVanillaAntiCheatWhileFalling": "추락하는 동안 바닐라 안티치트 비활성화", 11 | "forgivingvoid.configuration.dimensionAllowList": "차원 허용 목록", 12 | "forgivingvoid.configuration.dimensionDenyList": "차원 거부 목록" 13 | } -------------------------------------------------------------------------------- /common/src/main/resources/forgivingvoid.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "net.blay09.mods.forgivingvoid.mixin", 5 | "refmap": "${mod_id}.refmap.json", 6 | "compatibilityLevel": "JAVA_17", 7 | "mixins": [ 8 | "ServerGamePacketListenerImplAccessor", 9 | "ServerPlayerAccessor", 10 | "ThrownTridentAccessor", 11 | "CombatTrackerMixin" 12 | ], 13 | "client": [ 14 | ], 15 | "injectors": { 16 | "defaultRequire": 1 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/resources/forgivingvoid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwelveIterationMods/ForgivingVoid/9dd359f78af7ece3f2b45867c05df3a9ac3eb9ad/common/src/main/resources/forgivingvoid.png -------------------------------------------------------------------------------- /common/src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "${mod_name}", 4 | "pack_format": ${pack_format_number} 5 | } 6 | } -------------------------------------------------------------------------------- /fabric/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'multiloader-loader' 3 | id 'fabric-loom' 4 | id 'net.darkhax.curseforgegradle' 5 | id "com.modrinth.minotaur" 6 | } 7 | 8 | dependencies { 9 | minecraft "com.mojang:minecraft:${minecraft_version}" 10 | mappings loom.layered { 11 | officialMojangMappings() 12 | parchment("org.parchmentmc.data:parchment-${parchment_minecraft}:${parchment_version}@zip") 13 | } 14 | modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}" 15 | modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}" 16 | } 17 | 18 | apply from: rootProject.file('repositories.gradle') 19 | apply from: 'dependencies.gradle' 20 | 21 | loom { 22 | def aw = project(":common").file("src/main/resources/${mod_id}.accesswidener") 23 | if (aw.exists()) { 24 | accessWidenerPath.set(aw) 25 | } 26 | 27 | mixin { 28 | defaultRefmapName.set("${mod_id}.refmap.json") 29 | } 30 | 31 | runs { 32 | client { 33 | client() 34 | setConfigName("fabric Client") 35 | ideConfigGenerated(true) 36 | runDir("runs/client") 37 | } 38 | server { 39 | server() 40 | setConfigName("fabric Server") 41 | ideConfigGenerated(true) 42 | runDir("runs/server") 43 | } 44 | data { 45 | inherit client 46 | setConfigName("fabric Data") 47 | ideConfigGenerated(true) 48 | runDir("build/datagen") 49 | 50 | vmArg "-Dfabric-api.datagen" 51 | vmArg "-Dfabric-api.datagen.output-dir=${project(":common").file("src/generated/resources")}" 52 | vmArg "-Dfabric-api.datagen.modid=${mod_id}" 53 | } 54 | } 55 | } 56 | 57 | task curseforge(type: net.darkhax.curseforgegradle.TaskPublishCurseForge) { 58 | dependsOn('build') 59 | description = 'Publishes the Fabric build to CurseForge.' 60 | group = 'publishing' 61 | 62 | apiToken = project.findProperty("curseforge.api_key") ?: System.getenv("CURSEFORGE_TOKEN") ?: "none" 63 | 64 | def projectId = findProperty("curseforge_project_id") 65 | onlyIf { 66 | projectId != null 67 | } 68 | if (projectId) { 69 | def mainFile = upload(findProperty("curseforge_project_id"), file("${project.buildDir}/libs/${archivesBaseName}-${version}.jar")) 70 | mainFile.changelog = rootProject.file('CHANGELOG.md').text 71 | mainFile.addRequirement("fabric-api") 72 | mainFile.addRequirement("balm") 73 | project.minecraft_versions.split(',').toList().each { mainFile.addGameVersion(it) } 74 | mainFile.releaseType = "release" 75 | } 76 | } 77 | 78 | modrinth { 79 | token = project.findProperty("modrinth.token") ?: System.getenv("MODRINTH_TOKEN") ?: "none" 80 | projectId = findProperty("modrinth_project_id") 81 | versionType = "release" 82 | versionNumber = project.version + "+fabric-" + project.minecraft_version 83 | uploadFile = remapJar 84 | changelog = rootProject.file("CHANGELOG.md").text 85 | gameVersions = project.minecraft_versions.split(',').toList() 86 | syncBodyFrom = rootProject.file("modpage.md").text 87 | loaders = ['fabric'] 88 | dependencies { 89 | required.project "fabric-api" 90 | required.project "balm" 91 | } 92 | } -------------------------------------------------------------------------------- /fabric/dependencies.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | modImplementation("net.blay09.mods:balm-fabric:${balm_version}") { 3 | changing = balm_version.contains("SNAPSHOT") 4 | } 5 | modCompileOnly "com.terraformersmc:modmenu:$modmenu_version" 6 | } -------------------------------------------------------------------------------- /fabric/src/main/java/net/blay09/mods/forgivingvoid/fabric/FabricForgivingVoid.java: -------------------------------------------------------------------------------- 1 | package net.blay09.mods.forgivingvoid.fabric; 2 | 3 | import net.blay09.mods.balm.api.Balm; 4 | import net.blay09.mods.balm.api.EmptyLoadContext; 5 | import net.blay09.mods.forgivingvoid.ForgivingVoid; 6 | import net.fabricmc.api.ModInitializer; 7 | 8 | public class FabricForgivingVoid implements ModInitializer { 9 | @Override 10 | public void onInitialize() { 11 | Balm.initialize(ForgivingVoid.MOD_ID, EmptyLoadContext.INSTANCE, ForgivingVoid::initialize); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /fabric/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "${mod_id}", 4 | "version": "${version}", 5 | 6 | "name": "${mod_name}", 7 | "description": "${description}", 8 | "authors": [ 9 | "BlayTheNinth" 10 | ], 11 | "contact": { 12 | "homepage": "${homepage}", 13 | "sources": "${sources}", 14 | "issues": "${issues}" 15 | }, 16 | 17 | "license": "${license}", 18 | "icon": "${mod_id}.png", 19 | 20 | "environment": "*", 21 | "entrypoints": { 22 | "main": [ 23 | "net.blay09.mods.forgivingvoid.fabric.FabricForgivingVoid" 24 | ], 25 | "client": [ 26 | ] 27 | }, 28 | "mixins": [ 29 | "forgivingvoid.mixins.json", 30 | "forgivingvoid.fabric.mixins.json" 31 | ], 32 | 33 | "depends": { 34 | "fabricloader": ">=${fabric_loader_version}", 35 | "fabric-api": "*", 36 | "balm-fabric": "*", 37 | "minecraft": ">=${minimum_minecraft_version}", 38 | "java": ">=${java_version}" 39 | }, 40 | "suggests": { 41 | }, 42 | "custom": { 43 | "modmenu": { 44 | "links": { 45 | "modmenu.discord": "https://discord.gg/VAfZ2Nau6j" 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /fabric/src/main/resources/forgivingvoid.fabric.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "net.blay09.mods.forgivingvoid.fabric.mixin", 5 | "refmap": "${mod_id}.refmap.json", 6 | "compatibilityLevel": "JAVA_17", 7 | "mixins": [ 8 | ], 9 | "client": [ 10 | ], 11 | "injectors": { 12 | "defaultRequire": 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /forge/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'multiloader-loader' 3 | id 'net.minecraftforge.gradle' version '[6.0.25,6.2)' 4 | id 'org.spongepowered.mixin' version '0.7-SNAPSHOT' 5 | id 'net.darkhax.curseforgegradle' 6 | id "com.modrinth.minotaur" 7 | } 8 | 9 | mixin { 10 | config("${mod_id}.mixins.json") 11 | config("${mod_id}.forge.mixins.json") 12 | } 13 | 14 | jar { 15 | manifest { 16 | attributes["MixinConfigs"] = "${mod_id}.mixins.json,${mod_id}.forge.mixins.json" 17 | } 18 | } 19 | 20 | minecraft { 21 | mappings channel: 'official', version: minecraft_version 22 | 23 | reobf = false 24 | 25 | copyIdeResources = true 26 | 27 | // Automatically enable forge AccessTransformers if the file exists 28 | def at = file('src/main/resources/META-INF/accesstransformer.cfg') 29 | if (at.exists()) { 30 | accessTransformer = at 31 | } 32 | 33 | runs { 34 | client { 35 | workingDirectory file('runs/client') 36 | ideaModule "${rootProject.name}.${project.name}.main" 37 | taskName "Client" 38 | 39 | property 'forge.enabledGameTestNamespaces', mod_id 40 | 41 | mods { 42 | modClientRun { 43 | source sourceSets.main 44 | } 45 | } 46 | } 47 | 48 | server { 49 | workingDirectory file('runs/server') 50 | ideaModule "${rootProject.name}.${project.name}.main" 51 | taskName "Server" 52 | 53 | property 'forge.enabledGameTestNamespaces', mod_id 54 | 55 | mods { 56 | modServerRun { 57 | source sourceSets.main 58 | } 59 | } 60 | } 61 | 62 | data { 63 | workingDirectory file('runs/data') 64 | ideaModule "${rootProject.name}.${project.name}.main" 65 | args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') 66 | taskName "Data" 67 | 68 | mods { 69 | modDataRun { 70 | source sourceSets.main 71 | } 72 | } 73 | } 74 | } 75 | } 76 | 77 | sourceSets.main.resources.srcDir 'src/generated/resources' 78 | 79 | dependencies { 80 | minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" 81 | annotationProcessor "org.spongepowered:mixin:${mixin_version}:processor" 82 | // temporary hacky fix as suggested by Forge 83 | implementation('net.sf.jopt-simple:jopt-simple:5.0.4') { version { strictly '5.0.4' } } 84 | } 85 | 86 | apply from: rootProject.file('repositories.gradle') 87 | apply from: 'dependencies.gradle' 88 | 89 | publishing { 90 | publications { 91 | mavenJava(MavenPublication) { 92 | fg.component(it) 93 | } 94 | } 95 | } 96 | 97 | task curseforge(type: net.darkhax.curseforgegradle.TaskPublishCurseForge) { 98 | dependsOn('build') 99 | description = 'Publishes the Forge build to CurseForge.' 100 | group = 'publishing' 101 | 102 | apiToken = project.findProperty("curseforge.api_key") ?: System.getenv("CURSEFORGE_TOKEN") ?: "none" 103 | 104 | def projectId = findProperty("curseforge_project_id") 105 | onlyIf { 106 | projectId != null 107 | } 108 | if (projectId) { 109 | def mainFile = upload(findProperty("curseforge_project_id"), file("${project.buildDir}/libs/${archivesBaseName}-${version}.jar")) 110 | mainFile.changelog = rootProject.file('CHANGELOG.md').text 111 | mainFile.addRequirement("balm") 112 | project.minecraft_versions.split(',').toList().each { mainFile.addGameVersion(it) } 113 | mainFile.releaseType = "release" 114 | } 115 | } 116 | 117 | modrinth { 118 | token = project.findProperty("modrinth.token") ?: System.getenv("MODRINTH_TOKEN") ?: "none" 119 | projectId = findProperty("modrinth_project_id") 120 | versionType = "release" 121 | versionNumber = project.version + "+forge-" + project.minecraft_version 122 | uploadFile = jar 123 | changelog = rootProject.file("CHANGELOG.md").text 124 | gameVersions = project.minecraft_versions.split(',').toList() 125 | syncBodyFrom = rootProject.file("modpage.md").text 126 | loaders = ['forge'] 127 | dependencies { 128 | required.project "balm" 129 | } 130 | } 131 | 132 | sourceSets.each { 133 | def dir = layout.buildDirectory.dir("sourcesSets/$it.name") 134 | it.output.resourcesDir = dir 135 | it.java.destinationDirectory = dir 136 | } -------------------------------------------------------------------------------- /forge/dependencies.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | implementation("net.blay09.mods:balm-forge:${balm_version}") { 3 | changing = balm_version.contains("SNAPSHOT") 4 | } 5 | } -------------------------------------------------------------------------------- /forge/src/main/java/net/blay09/mods/forgivingvoid/ForgeForgivingVoid.java: -------------------------------------------------------------------------------- 1 | package net.blay09.mods.forgivingvoid; 2 | 3 | import net.blay09.mods.balm.api.Balm; 4 | import net.blay09.mods.balm.forge.ForgeLoadContext; 5 | import net.minecraftforge.fml.IExtensionPoint; 6 | import net.minecraftforge.fml.common.Mod; 7 | import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; 8 | 9 | @Mod(ForgivingVoid.MOD_ID) 10 | public class ForgeForgivingVoid { 11 | 12 | public ForgeForgivingVoid(FMLJavaModLoadingContext context) { 13 | final var loadContext = new ForgeLoadContext(context.getModEventBus()); 14 | Balm.initialize(ForgivingVoid.MOD_ID, loadContext, ForgivingVoid::initialize); 15 | 16 | context.registerDisplayTest(IExtensionPoint.DisplayTest.IGNORE_ALL_VERSION); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /forge/src/main/resources/META-INF/mods.toml: -------------------------------------------------------------------------------- 1 | modLoader="javafml" 2 | loaderVersion="${forge_loader_version_range}" 3 | license="${license}" 4 | issueTrackerURL="${issues}" 5 | [[mods]] 6 | modId="${mod_id}" 7 | version="${version}" 8 | displayName="${mod_name}" 9 | displayURL="${homepage}" 10 | logoFile="${mod_id}.png" 11 | credits="BlayTheNinth" 12 | authors="BlayTheNinth" 13 | description='''${description}''' 14 | [[dependencies.${mod_id}]] 15 | modId="forge" 16 | mandatory=true 17 | versionRange="${forge_version_range}" 18 | ordering="NONE" 19 | side="BOTH" 20 | [[dependencies.${mod_id}]] 21 | modId="minecraft" 22 | mandatory=true 23 | versionRange="${minecraft_version_range}" 24 | ordering="NONE" 25 | side="BOTH" 26 | [[dependencies.${mod_id}]] 27 | modId="balm" 28 | mandatory=true 29 | versionRange="${balm_version_range}" 30 | ordering="NONE" 31 | side="BOTH" 32 | -------------------------------------------------------------------------------- /forge/src/main/resources/forgivingvoid.forge.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "net.blay09.mods.forgivingvoid.forge.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "mixins": [ 7 | ], 8 | "client": [ 9 | ], 10 | "injectors": { 11 | "defaultRequire": 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Mod 2 | mod_id = forgivingvoid 3 | mod_name = Forgiving Void 4 | mod_main=ForgivingVoid 5 | description=Makes the void hate you a little less (and vice-versa). Fall down and come back out on top. 6 | version = 21.5.3 7 | group = net.blay09.mods 8 | homepage=https://mods.twelveiterations.com/mc/forgiving-void 9 | sources=https://github.com/TwelveIterationMods/ForgivingVoid 10 | issues=https://github.com/TwelveIterationMods/ForgivingVoid/issues 11 | discord = https://discord.gg/VAfZ2Nau6j 12 | license=All Rights Reserved 13 | 14 | # Publishing 15 | curseforge_project_id = 271009 16 | modrinth_project_id = 1vkzEZjE 17 | maven_releases = https://maven.twelveiterations.com/repository/maven-releases/ 18 | maven_snapshots = https://maven.twelveiterations.com/repository/maven-snapshots/ 19 | 20 | # Minecraft 21 | minecraft_version = 1.21.5 22 | minecraft_versions = 1.21.5 23 | minecraft_version_range = [1.21.5,) 24 | pack_format_number = 71 25 | java_version = 21 26 | 27 | # Balm 28 | balm_version = 21.5.5-SNAPSHOT 29 | balm_version_range = [21.5.0,) 30 | 31 | # Forge 32 | forge_version = 55.0.3 33 | forge_version_range = [55,) 34 | forge_loader_version_range = [55,) 35 | 36 | # NeoForge 37 | neoforge_snapshot_url=https://prmaven.neoforged.net/NeoForge/pr2039 38 | neoforge_version = 21.5.0-beta 39 | neoforge_version_range = [21,) 40 | neoforge_loader_version_range = [1,) 41 | 42 | # Fabric 43 | fabric_version = 0.119.5+1.21.5 44 | fabric_loader_version = 0.16.10 45 | 46 | # Dependencies 47 | mixin_version=0.8.5 48 | modmenu_version=9.0.0 49 | 50 | # Gradle 51 | org.gradle.jvmargs=-Xmx3G 52 | org.gradle.daemon=false 53 | mod_author = BlayTheNinth 54 | credits = BlayTheNinth 55 | kuma_version = [21.5,21.6) 56 | neo_form_version = 1.21.5-20250325.162830 57 | parchment_minecraft = 1.21.4 58 | parchment_version = 2025.02.16 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TwelveIterationMods/ForgivingVoid/9dd359f78af7ece3f2b45867c05df3a9ac3eb9ad/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MSYS* | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /modpage.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | Requires Balm 4 | 5 | 6 | 7 | Become a Patron 8 | 9 | 10 | 11 | Follow me on Twitter 12 | 13 | 14 | Join our Discord 15 | 16 |

17 | 18 | ![](https://blay09.net/files/brand/forgivingvoid.png) 19 | 20 | Have you ever wondered what would happen if instead of dying in the void, you just kept falling? Turns out you just come back out from the top (and the fall doesn't even kill you due to magic miracle power). 21 | 22 | Instead of dying in the void, you will fall back down from the sky. Despite the large falling height, you can still survive as long as you had full health when landing. 23 | 24 | ## Features 25 | 26 | - Fall back down from the sky when falling into the void 27 | - Always survive the fall as long as you had full health 28 | 29 | [Video of Forgiving Void in Action](https://twitter.com/BlayTheNinth/status/880510912762925056) 30 | 31 | ![](https://blay09.net/files/brand/forgivingvoid.gif) -------------------------------------------------------------------------------- /neoforge/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'multiloader-loader' 3 | id 'net.neoforged.moddev' 4 | id 'net.darkhax.curseforgegradle' 5 | id "com.modrinth.minotaur" 6 | } 7 | 8 | base { 9 | archivesName = "${mod_id}-neoforge-${minecraft_version}" 10 | } 11 | 12 | neoForge { 13 | version = neoforge_version 14 | // Automatically enable neoforge AccessTransformers if the file exists 15 | def at = project(':common').file('src/main/resources/META-INF/accesstransformer.cfg') 16 | if (at.exists()) { 17 | accessTransformers.from(at.absolutePath) 18 | } 19 | 20 | parchment { 21 | minecraftVersion = parchment_minecraft 22 | mappingsVersion = parchment_version 23 | } 24 | 25 | runs { 26 | configureEach { 27 | systemProperty('neoforge.enabledGameTestNamespaces', mod_id) 28 | ideName = "NeoForge ${it.name.capitalize()} (${project.path})" 29 | } 30 | 31 | client { 32 | client() 33 | } 34 | 35 | server { 36 | server() 37 | } 38 | } 39 | 40 | mods { 41 | "${mod_id}" { 42 | sourceSet sourceSets.main 43 | } 44 | } 45 | } 46 | 47 | sourceSets.main.resources { srcDir 'src/generated/resources' } 48 | 49 | apply from: rootProject.file('repositories.gradle') 50 | apply from: 'dependencies.gradle' 51 | 52 | task curseforge(type: net.darkhax.curseforgegradle.TaskPublishCurseForge) { 53 | dependsOn('build') 54 | description = 'Publishes the NeoForge build to CurseForge.' 55 | group = 'publishing' 56 | 57 | apiToken = project.findProperty("curseforge.api_key") ?: System.getenv("CURSEFORGE_TOKEN") ?: "none" 58 | 59 | def projectId = findProperty("curseforge_project_id") 60 | onlyIf { 61 | projectId != null 62 | } 63 | if (projectId) { 64 | def mainFile = upload(findProperty("curseforge_project_id"), file("${project.buildDir}/libs/${archivesBaseName}-${version}.jar")) 65 | mainFile.changelog = rootProject.file('CHANGELOG.md').text 66 | mainFile.addRequirement("balm") 67 | project.minecraft_versions.split(',').toList().each { mainFile.addGameVersion(it) } 68 | mainFile.releaseType = "release" 69 | mainFile.addModLoader("NeoForge") 70 | } 71 | } 72 | 73 | modrinth { 74 | token = project.findProperty("modrinth.token") ?: System.getenv("MODRINTH_TOKEN") ?: "none" 75 | projectId = findProperty("modrinth_project_id") 76 | versionType = "release" 77 | versionNumber = project.version + "+neoforge-" + project.minecraft_version 78 | uploadFile = jar 79 | changelog = rootProject.file("CHANGELOG.md").text 80 | gameVersions = project.minecraft_versions.split(',').toList() 81 | syncBodyFrom = rootProject.file("modpage.md").text 82 | loaders = ['neoforge'] 83 | dependencies { 84 | required.project "balm" 85 | } 86 | } 87 | 88 | configurations { 89 | // This is a workaround for issues with certain dependencies. It may not be necessary in your case. 90 | testCompileOnly.extendsFrom compileOnly 91 | } 92 | 93 | def neoForgeSnapshotUrl = findProperty("neoforge_snapshot_url") 94 | if (neoForgeSnapshotUrl != null) { 95 | repositories { 96 | maven { 97 | name 'Maven for NeoForge Snapshots' 98 | url neoForgeSnapshotUrl 99 | content { 100 | includeModule('net.neoforged', 'neoforge') 101 | includeModule('net.neoforged', 'testframework') 102 | } 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /neoforge/dependencies.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | implementation("net.blay09.mods:balm-neoforge:${balm_version}") { 3 | changing = balm_version.contains("SNAPSHOT") 4 | } 5 | } -------------------------------------------------------------------------------- /neoforge/src/main/java/net/blay09/mods/forgivingvoid/NeoForgeForgivingVoid.java: -------------------------------------------------------------------------------- 1 | package net.blay09.mods.forgivingvoid; 2 | 3 | import net.blay09.mods.balm.api.Balm; 4 | import net.blay09.mods.balm.neoforge.NeoForgeLoadContext; 5 | import net.neoforged.bus.EventBus; 6 | import net.neoforged.bus.api.IEventBus; 7 | import net.neoforged.fml.IExtensionPoint; 8 | import net.neoforged.fml.ModLoadingContext; 9 | import net.neoforged.fml.common.Mod; 10 | 11 | @Mod(ForgivingVoid.MOD_ID) 12 | public class NeoForgeForgivingVoid { 13 | 14 | public NeoForgeForgivingVoid(IEventBus modEventBus) { 15 | final var context = new NeoForgeLoadContext(modEventBus); 16 | Balm.initialize(ForgivingVoid.MOD_ID, context, ForgivingVoid::initialize); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /neoforge/src/main/resources/META-INF/neoforge.mods.toml: -------------------------------------------------------------------------------- 1 | modLoader="javafml" 2 | loaderVersion="${neoforge_loader_version_range}" 3 | license="${license}" 4 | issueTrackerURL="${issues}" 5 | [[mods]] 6 | modId="${mod_id}" 7 | version="${version}" 8 | displayName="${mod_name}" 9 | displayURL="${homepage}" 10 | displayTest="NONE" 11 | logoFile="${mod_id}.png" 12 | credits="BlayTheNinth" 13 | authors="BlayTheNinth" 14 | description='''${description}''' 15 | [[mixins]] 16 | config = "${mod_id}.mixins.json" 17 | [[mixins]] 18 | config = "${mod_id}.neoforge.mixins.json" 19 | [[dependencies.${mod_id}]] 20 | modId="neoforge" 21 | type="required" 22 | versionRange="${neoforge_version_range}" 23 | ordering="NONE" 24 | side="BOTH" 25 | [[dependencies.${mod_id}]] 26 | modId="minecraft" 27 | type="required" 28 | versionRange="${minecraft_version_range}" 29 | ordering="NONE" 30 | side="BOTH" 31 | [[dependencies.${mod_id}]] 32 | modId="balm" 33 | type="required" 34 | versionRange="${balm_version_range}" 35 | ordering="NONE" 36 | side="BOTH" 37 | -------------------------------------------------------------------------------- /neoforge/src/main/resources/forgivingvoid.neoforge.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "net.blay09.mods.forgivingvoid.neoforge.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "mixins": [ 7 | ], 8 | "client": [ 9 | ], 10 | "injectors": { 11 | "defaultRequire": 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /repositories.gradle: -------------------------------------------------------------------------------- 1 | repositories { 2 | maven { 3 | url = "https://www.cursemaven.com" 4 | content { 5 | includeGroup 'curse.maven' 6 | } 7 | } 8 | 9 | maven { 10 | url = "https://maven.shedaniel.me/" 11 | content { 12 | includeGroup "me.shedaniel" 13 | includeGroup "me.shedaniel.cloth" 14 | includeGroup "dev.architectury" 15 | } 16 | } 17 | 18 | maven { 19 | url = "https://maven.blamejared.com" 20 | content { 21 | includeGroup "mezz.jei" 22 | } 23 | } 24 | 25 | maven { 26 | url = "https://maven.bai.lol" 27 | content { 28 | includeGroup "lol.bai" 29 | includeGroup "mcp.mobius.waila" 30 | } 31 | } 32 | 33 | maven { 34 | url = "https://maven.terraformersmc.com/releases" 35 | content { 36 | includeGroup "com.terraformersmc" 37 | includeGroup "dev.emi" 38 | } 39 | } 40 | 41 | maven { 42 | url = "https://jm.gserv.me/repository/maven-public/" 43 | content { 44 | includeGroup "info.journeymap" 45 | includeGroup "mysticdrew" 46 | } 47 | } 48 | 49 | maven { 50 | url = 'https://jitpack.io' 51 | content { 52 | includeGroup "com.github.BlueMap-Minecraft" 53 | includeGroup "com.github.mattidragon" 54 | } 55 | } 56 | 57 | maven { 58 | url = "https://repo.mikeprimm.com/" 59 | content { 60 | includeGroup "us.dynmap" 61 | } 62 | } 63 | 64 | maven { 65 | url = 'https://maven.ladysnake.org/releases' 66 | content { 67 | includeGroup "dev.onyxstudios.cardinal-components-api" 68 | includeGroup "org.ladysnake.cardinal-components-api" 69 | } 70 | } 71 | 72 | maven { 73 | url "https://maven.siphalor.de/" 74 | content { 75 | includeGroup "de.siphalor" 76 | } 77 | } 78 | 79 | maven { 80 | url = "https://maven.theillusivec4.top/" 81 | content { 82 | includeGroup "top.theillusivec4.curios" 83 | } 84 | } 85 | 86 | maven { 87 | url = "https://dl.cloudsmith.io/public/novamachina-mods/release/maven/" 88 | content { 89 | includeGroup "novamachina.novacore" 90 | includeGroup "novamachina.exnihilosequentia" 91 | } 92 | } 93 | 94 | exclusiveContent { 95 | forRepository { 96 | maven { 97 | name = 'Minecraft' 98 | url = 'https://libraries.minecraft.net/' 99 | } 100 | } 101 | filter { includeGroupAndSubgroups("com.mojang") } 102 | } 103 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | mavenCentral() 5 | exclusiveContent { 6 | forRepository { 7 | maven { 8 | name = 'Fabric' 9 | url = uri("https://maven.fabricmc.net") 10 | } 11 | } 12 | filter { 13 | includeGroup("net.fabricmc") 14 | includeGroup("fabric-loom") 15 | } 16 | } 17 | exclusiveContent { 18 | forRepository { 19 | maven { 20 | name = 'Sponge' 21 | url = uri('https://repo.spongepowered.org/repository/maven-public') 22 | } 23 | } 24 | filter { 25 | includeGroupAndSubgroups("org.spongepowered") 26 | } 27 | } 28 | exclusiveContent { 29 | forRepository { 30 | maven { 31 | name = 'Forge' 32 | url = uri("https://maven.minecraftforge.net") 33 | } 34 | } 35 | filter { 36 | includeGroupAndSubgroups("net.minecraftforge") 37 | } 38 | } 39 | } 40 | } 41 | 42 | plugins { 43 | id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' 44 | } 45 | 46 | include('common', 'fabric', 'forge', 'neoforge') 47 | --------------------------------------------------------------------------------