From f8986009a4f79ab761b52456e0f484b1adb9f23f Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Fri, 11 Sep 2026 14:13:28 +0100 Subject: [PATCH 1/6] Modernize Base Metals 1.12 build and release pipeline --- .gitattributes | 27 + .github/workflows/ci.yml | 199 ++ .github/workflows/codeql-analysis.yml | 80 + .github/workflows/deploy-release.yml | 87 +- .github/workflows/release-on-tag.yml | 87 + .github/workflows/validate-gradle-build.yml | 23 + .gitignore | 92 +- .travis.yml | 29 - CHANGELOG.txt | 14 + build.gradle | 1901 +++++++++++------ gradle.properties | 137 +- gradle/prepare-packaged-forge-runtime.sh | 37 + gradle/stage-legacy-dependencies.sh | 59 + gradle/wrapper/gradle-wrapper.jar | Bin 54413 -> 48462 bytes gradle/wrapper/gradle-wrapper.properties | 7 +- gradlew | 303 ++- gradlew.bat | 166 +- settings.gradle | 34 +- .../com/mcmoddev/basemetals/BaseMetals.java | 4 +- .../orespawn/BaseMetalsOreSpawn.java | 12 +- src/main/resources/mcmod.info | 2 +- .../test/BaseMetalsRuntimeProbe.java | 93 + 22 files changed, 2432 insertions(+), 961 deletions(-) create mode 100644 .gitattributes create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/release-on-tag.yml create mode 100644 .github/workflows/validate-gradle-build.yml delete mode 100644 .travis.yml create mode 100644 gradle/prepare-packaged-forge-runtime.sh create mode 100644 gradle/stage-legacy-dependencies.sh rename src/main/java/com/mcmoddev/{ => basemetals/integration}/orespawn/BaseMetalsOreSpawn.java (52%) create mode 100644 src/test/java/com/mcmoddev/basemetals/test/BaseMetalsRuntimeProbe.java diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..0457356b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,27 @@ +* text=auto eol=lf + +*.bat text eol=crlf +*.gradle text diff=java +mcmod.info text +*.java text +*.json text +*.lang text +*.mcmeta text +*.md text +*.properties text +gradlew text eol=lf +*.sh text eol=lf +*.txt text +*.xml text +*.yml text +*.yaml text + +*.gif binary +*.ico binary +*.jpg binary +*.jpeg binary +*.png binary +*.psd binary +*.svg binary +*.jar binary +*.zip binary diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..6104faf6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,199 @@ +name: Base Metals 1.12 CI + +on: + push: + branches: + - master-1.12 + - 'feature/**' + pull_request: + branches: + - master-1.12 + +permissions: + contents: read + +concurrency: + group: basemetals-1.12-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + cold-forge-bootstrap: + name: Cold Forge bootstrap + runs-on: ubuntu-latest + timeout-minutes: 75 + + steps: + - name: Check out source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + + - name: Install pinned Java 25 ForgeGradle Mavenizer runtime + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + with: + distribution: temurin + java-version: '25.0.3+9.0.LTS' + + - name: Install pinned Java 8 compilation toolchain + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + with: + distribution: temurin + java-version: '8.0.502+7' + + - name: Install pinned Java 17 Gradle runtime + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + with: + distribution: temurin + java-version: '17.0.1+12' + + - name: Stage checksum-verified legacy dependencies + id: dependencies + shell: bash + run: | + set -euo pipefail + mirror="$RUNNER_TEMP/legacy-dependency-mirror" + bash gradle/stage-legacy-dependencies.sh "$mirror" + echo "repository=$mirror" >> "$GITHUB_OUTPUT" + + - name: Bootstrap Forge from an empty cache + shell: bash + env: + GRADLE_USER_HOME: ${{ runner.temp }}/basemetals-cold-gradle + run: | + set -euo pipefail + test ! -e .gradle + test ! -e "$GRADLE_USER_HOME" + mkdir -p "$GRADLE_USER_HOME" + chmod +x ./gradlew + gradle_args=( + classes verifyReleaseDependencies + -PlegacyDependencyVerificationRepository="${{ steps.dependencies.outputs.repository }}" + --no-daemon --no-build-cache --stacktrace --max-workers=2 + -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_25_X64" + -Dorg.gradle.java.installations.auto-detect=false + -Dorg.gradle.java.installations.auto-download=false + ) + ./gradlew "${gradle_args[@]}" + + - name: Verify same-cache bootstrap offline + shell: bash + env: + GRADLE_USER_HOME: ${{ runner.temp }}/basemetals-cold-gradle + run: | + set -euo pipefail + gradle_args=( + classes verifyReleaseDependencies + -PlegacyDependencyVerificationRepository="${{ steps.dependencies.outputs.repository }}" + --rerun-tasks --offline --no-daemon --no-build-cache --stacktrace --max-workers=2 + -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_25_X64" + -Dorg.gradle.java.installations.auto-detect=false + -Dorg.gradle.java.installations.auto-download=false + ) + ./gradlew "${gradle_args[@]}" + + build: + name: Build, test, and audit + runs-on: ubuntu-latest + timeout-minutes: 90 + + steps: + - name: Check out source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + + - name: Install pinned Java 25 ForgeGradle Mavenizer runtime + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + with: + distribution: temurin + java-version: '25.0.3+9.0.LTS' + + - name: Install pinned Java 8 compilation and runtime toolchain + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + with: + distribution: temurin + java-version: '8.0.502+7' + + - name: Install pinned Java 17 Gradle runtime + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + with: + distribution: temurin + java-version: '17.0.1+12' + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6 + + - name: Stage checksum-verified dependencies + id: dependencies + shell: bash + run: | + set -euo pipefail + mirror="$RUNNER_TEMP/legacy-dependency-mirror" + bash gradle/stage-legacy-dependencies.sh "$mirror" + echo "repository=$mirror" >> "$GITHUB_OUTPUT" + + - name: Prepare clean packaged Forge runtime + id: forge + shell: bash + run: | + set -euo pipefail + runtime="$RUNNER_TEMP/forge-1.12.2-2859-runtime" + bash gradle/prepare-packaged-forge-runtime.sh "$runtime" "$JAVA_HOME_8_X64/bin/java" + echo "runtime=$runtime" >> "$GITHUB_OUTPUT" + + - name: Build, test, audit, qualify runtimes, and generate Eclipse launches + shell: bash + run: | + set -euo pipefail + chmod +x ./gradlew + gradle_args=( + clean check build javadoc verifyReleaseDependencies verifyReleaseArtifacts + writeReleaseChecksums prepareEclipse packagedForgeRuntimeTest + -PlegacyDependencyVerificationRepository="${{ steps.dependencies.outputs.repository }}" + -PpackagedForgeRuntimeRoot="${{ steps.forge.outputs.runtime }}" + --no-daemon --stacktrace --max-workers=2 + -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_25_X64" + -Dorg.gradle.java.installations.auto-detect=false + -Dorg.gradle.java.installations.auto-download=false + ) + ./gradlew "${gradle_args[@]}" + cp build/release/SHA256SUMS "$RUNNER_TEMP/first-SHA256SUMS" + + - name: Verify reproducible release archives + shell: bash + run: | + set -euo pipefail + gradle_args=( + clean build javadoc verifyReleaseArtifacts writeReleaseChecksums + -PlegacyDependencyVerificationRepository="${{ steps.dependencies.outputs.repository }}" + --offline --no-daemon --no-build-cache --stacktrace --max-workers=2 + -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_25_X64" + -Dorg.gradle.java.installations.auto-detect=false + -Dorg.gradle.java.installations.auto-download=false + ) + ./gradlew "${gradle_args[@]}" + cmp "$RUNNER_TEMP/first-SHA256SUMS" build/release/SHA256SUMS + + - name: Upload audited release candidate + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: BaseMetals-1.12.2-${{ github.sha }} + if-no-files-found: error + retention-days: 30 + path: | + build/libs/BaseMetals-2.5.1.112021.jar + build/libs/BaseMetals-2.5.1.112021-sources.jar + build/libs/BaseMetals-2.5.1.112021-javadoc.jar + build/release/SHA256SUMS + CHANGELOG.txt + + - name: Upload bounded diagnostics on failure + if: failure() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: BaseMetals-1.12.2-diagnostics-${{ github.sha }} + if-no-files-found: ignore + retention-days: 14 + path: | + build/test-results/** + build/reports/** + build/packaged-forge-*-run/logs/** + build/packaged-forge-*-run/*-console.txt + build/packaged-forge-*-run/crash-reports/** + build/problems/** diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..5a29b994 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,80 @@ +name: CodeQL + +on: + push: + branches: + - master-1.12 + - 'feature/**' + pull_request: + branches: + - master-1.12 + schedule: + - cron: '47 7 * * 4' + +permissions: + actions: read + contents: read + security-events: write + +jobs: + analyze: + name: Analyze Java + runs-on: ubuntu-latest + timeout-minutes: 60 + + steps: + - name: Check out source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + + - name: Install pinned Java 25 ForgeGradle Mavenizer runtime + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + with: + distribution: temurin + java-version: '25.0.3+9.0.LTS' + + - name: Install pinned Java 8 compilation toolchain + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + with: + distribution: temurin + java-version: '8.0.502+7' + + - name: Install pinned Java 17 Gradle runtime + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + with: + distribution: temurin + java-version: '17.0.1+12' + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6 + + - name: Initialize CodeQL + uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4 + with: + languages: java-kotlin + + - name: Stage checksum-verified dependencies + id: dependencies + shell: bash + run: | + set -euo pipefail + mirror="$RUNNER_TEMP/legacy-dependency-mirror" + bash gradle/stage-legacy-dependencies.sh "$mirror" + echo "repository=$mirror" >> "$GITHUB_OUTPUT" + + - name: Compile production code + shell: bash + run: | + set -euo pipefail + chmod +x ./gradlew + gradle_args=( + clean classes + -PlegacyDependencyVerificationRepository="${{ steps.dependencies.outputs.repository }}" + --no-daemon --stacktrace --max-workers=2 + -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_25_X64" + -Dorg.gradle.java.installations.auto-detect=false + -Dorg.gradle.java.installations.auto-download=false + ) + ./gradlew "${gradle_args[@]}" + + - name: Analyze + uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4 diff --git a/.github/workflows/deploy-release.yml b/.github/workflows/deploy-release.yml index 59868215..710e8e37 100644 --- a/.github/workflows/deploy-release.yml +++ b/.github/workflows/deploy-release.yml @@ -51,6 +51,7 @@ jobs: gradle_java_version: ${{ steps.validate.outputs.gradle_java_version }} install_gradle_java: ${{ steps.validate.outputs.install_gradle_java }} curseforge_project_id: ${{ steps.validate.outputs.curseforge_project_id }} + curseforge_dependencies: ${{ steps.validate.outputs.curseforge_dependencies }} main_jar: ${{ steps.validate.outputs.main_jar }} sources_jar: ${{ steps.validate.outputs.sources_jar }} javadoc_jar: ${{ steps.validate.outputs.javadoc_jar }} @@ -142,6 +143,7 @@ jobs: java_setup_version="$(value java_setup_version)" gradle_java_version="$(value gradle_java_version)" curseforge_project_id="$(value curseforge_project_id)" + cf_requirements="$(value cf_requirements)" for required in release_version minecraft_version loader_name loader_code \ java_version gradle_java_version curseforge_project_id; do @@ -234,8 +236,39 @@ jobs: echo "Requested version $REQUESTED_VERSION does not match ${{ steps.route.outputs.target_branch }} mod_version $release_version" >&2 exit 1 fi - if [[ "${{ steps.route.outputs.target_branch }}" != "master-1.18" ]]; then - echo "This dispatcher supports Base Metals 1.18.2 releases from master-1.18" >&2 + case "${{ steps.route.outputs.target_branch }}" in + master-1.12) + if [[ "$minecraft_version" != '1.12.2' || "$java_toolchain_version" != '8.0.502+7' \ + || "$gradle_java_version" != '17' ]]; then + echo "master-1.12 has an unexpected target/toolchain contract" >&2 + exit 1 + fi + ;; + master-1.18) + if [[ "$minecraft_version" != '1.18.2' || "$java_toolchain_version" != '17.0.1+12' \ + || "$gradle_java_version" != '17' ]]; then + echo "master-1.18 has an unexpected target/toolchain contract" >&2 + exit 1 + fi + ;; + *) + echo "This dispatcher supports Base Metals master-1.12 and master-1.18" >&2 + exit 1 + ;; + esac + + curseforge_dependencies=() + IFS=',' read -ra requirement_slugs <<<"$cf_requirements" + for slug in "${requirement_slugs[@]}"; do + case "$slug" in + mmd-orespawn) curseforge_dependencies+=('245586(required)') ;; + mmdlib) curseforge_dependencies+=('261744(required)') ;; + '') ;; + *) echo "Unsupported required CurseForge relation $slug" >&2; exit 1 ;; + esac + done + if (( ${#curseforge_dependencies[@]} == 0 )); then + echo "No required CurseForge relations were declared" >&2 exit 1 fi @@ -253,6 +286,11 @@ jobs: echo "gradle_java_version=$gradle_java_version" >> "$GITHUB_OUTPUT" echo "install_gradle_java=$install_gradle_java" >> "$GITHUB_OUTPUT" echo "curseforge_project_id=$curseforge_project_id" >> "$GITHUB_OUTPUT" + { + echo 'curseforge_dependencies<> "$GITHUB_OUTPUT" echo "main_jar=BaseMetals-$release_version.jar" >> "$GITHUB_OUTPUT" echo "sources_jar=BaseMetals-$release_version-sources.jar" >> "$GITHUB_OUTPUT" echo "javadoc_jar=BaseMetals-$release_version-javadoc.jar" >> "$GITHUB_OUTPUT" @@ -344,12 +382,23 @@ jobs: done echo "paths=$paths" >> "$GITHUB_OUTPUT" - - name: Stage exact OreSpawn release dependency - id: orespawn + - name: Stage exact target dependencies + id: dependencies run: | - mirror="$RUNNER_TEMP/orespawn-mirror" - bash gradle/stage-orespawn-release.sh "$mirror" + set -euo pipefail + mirror="$RUNNER_TEMP/dependency-mirror" + if [[ -f gradle/stage-legacy-dependencies.sh ]]; then + bash gradle/stage-legacy-dependencies.sh "$mirror" + property=legacyDependencyVerificationRepository + elif [[ -f gradle/stage-orespawn-release.sh ]]; then + bash gradle/stage-orespawn-release.sh "$mirror" + property=orespawnVerificationRepository + else + echo "Selected target has no checksum-sealed dependency staging script" >&2 + exit 1 + fi echo "repository=$mirror" >> "$GITHUB_OUTPUT" + echo "property=$property" >> "$GITHUB_OUTPUT" - name: Build, test, and audit once run: | @@ -360,8 +409,9 @@ jobs: -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.java.installations.auto-download=false ) + dependency_argument="-P${{ steps.dependencies.outputs.property }}=${{ steps.dependencies.outputs.repository }}" ./gradlew clean check build javadoc verifyReleaseArtifacts writeReleaseChecksums \ - -PorespawnVerificationRepository="${{ steps.orespawn.outputs.repository }}" \ + "$dependency_argument" \ --no-daemon --stacktrace "${java_args[@]}" - name: Stage the immutable release artifact @@ -557,6 +607,25 @@ jobs: name: ${{ needs.build.outputs.artifact_name }} path: ${{ runner.temp }}/release-input + - name: Stage exact target dependencies + id: dependencies + shell: bash + run: | + set -euo pipefail + mirror="$RUNNER_TEMP/dependency-mirror" + if [[ -f gradle/stage-legacy-dependencies.sh ]]; then + bash gradle/stage-legacy-dependencies.sh "$mirror" + property=legacyDependencyVerificationRepository + elif [[ -f gradle/stage-orespawn-release.sh ]]; then + bash gradle/stage-orespawn-release.sh "$mirror" + property=orespawnVerificationRepository + else + echo "Selected target has no checksum-sealed dependency staging script" >&2 + exit 1 + fi + echo "repository=$mirror" >> "$GITHUB_OUTPUT" + echo "property=$property" >> "$GITHUB_OUTPUT" + - name: Verify artifact and Maven credentials env: MAVEN_UPLOAD_URL: ${{ secrets.MAVEN_UPLOAD_URL }} @@ -581,8 +650,10 @@ jobs: MAVEN_UPLOAD_PASSWORD: ${{ secrets.MAVEN_UPLOAD_PASSWORD }} run: | chmod +x ./gradlew + dependency_argument="-P${{ steps.dependencies.outputs.property }}=${{ steps.dependencies.outputs.repository }}" ./gradlew publishMavenJavaPublicationToReleaseRepository \ -PpreparedReleaseDir="$RUNNER_TEMP/release-input" \ + "$dependency_argument" \ --no-daemon --stacktrace \ -Dorg.gradle.java.installations.paths="${{ steps.java-paths.outputs.paths }}" \ -Dorg.gradle.java.installations.auto-detect=false \ @@ -629,7 +700,7 @@ jobs: game-version-filter: none environment: client | server java: Java ${{ needs.preflight.outputs.java_version }} - curseforge-dependencies: 245586(required) + curseforge-dependencies: ${{ needs.preflight.outputs.curseforge_dependencies }} fail-mode: fail files: | ${{ runner.temp }}/release-input/${{ needs.preflight.outputs.main_jar }} diff --git a/.github/workflows/release-on-tag.yml b/.github/workflows/release-on-tag.yml new file mode 100644 index 00000000..06f795b1 --- /dev/null +++ b/.github/workflows/release-on-tag.yml @@ -0,0 +1,87 @@ +name: Start Base Metals release from tag + +on: + push: + tags: + - '*.*.*.*' + +permissions: + actions: read + contents: read + +concurrency: + group: basemetals-release-starter-${{ github.ref_name }} + cancel-in-progress: false + +jobs: + validate-release-tag: + name: Validate tag for manual release confirmation + if: github.repository == 'MinecraftModDevelopmentMods/BaseMetals' + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Check out tagged source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + fetch-depth: 0 + + - name: Validate release tag, target metadata, and prior CI + env: + GH_TOKEN: ${{ github.token }} + shell: bash + run: | + set -euo pipefail + + value() { sed -n "s/^$1=//p" gradle.properties; } + release_version="$(value mod_version)" + minecraft_version="$(value minecraft_version)" + loader_name="$(value loader_name)" + loader_code="$(value loader_code)" + + IFS=. read -r mc_major mc_minor mc_patch extra <<<"$minecraft_version" + mc_patch="${mc_patch:-0}" + if [[ -n "${extra:-}" || ! "$mc_major" =~ ^[0-9]+$ || ! "$mc_minor" =~ ^[0-9]+$ \ + || ! "$mc_patch" =~ ^[0-9]+$ || "$loader_name:$loader_code" != 'forge:1' ]]; then + echo "Invalid target metadata $minecraft_version/$loader_name/$loader_code" >&2 + exit 1 + fi + printf -v minor_padded '%02d' "$((10#$mc_minor))" + printf -v patch_padded '%02d' "$((10#$mc_patch))" + target_suffix="${mc_major}${minor_padded}${patch_padded}${loader_code}" + + if [[ ! "$release_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.${target_suffix}$ ]]; then + echo "mod_version $release_version does not match target $target_suffix" >&2 + exit 1 + fi + if [[ "$GITHUB_REF_NAME" != "$release_version" ]]; then + echo "Release tag must equal mod_version $release_version; found $GITHUB_REF_NAME" >&2 + exit 1 + fi + + successful_ci="$(gh api \ + "repos/$GITHUB_REPOSITORY/commits/$GITHUB_SHA/check-runs?per_page=100" \ + --jq '[.check_runs[] | select(.name == "Build, test, and audit" and .conclusion == "success")] | length')" + if [[ "$successful_ci" -lt 1 ]]; then + echo "The tagged commit has no successful Build, test, and audit check" >&2 + exit 1 + fi + + - name: Record the required manual publication step + env: + RELEASE_WORKFLOW_URL: https://github.com/${{ github.repository }}/actions/workflows/deploy-release.yml + shell: bash + run: | + { + echo "## Release candidate validated" + echo + echo "Tag \`$GITHUB_REF_NAME\` matches the selected target and has a successful Build, test, and audit check." + echo + echo "**Nothing has been published.**" + echo + echo "To continue, open [Release Base Metals]($RELEASE_WORKFLOW_URL), select **Run workflow**, and enter:" + echo + echo "- release_version: \`$GITHUB_REF_NAME\`" + echo "- curseforge_release_level: \`release\`, \`beta\`, or \`alpha\`" + echo "- confirm_live_publication: \`true\`" + } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/validate-gradle-build.yml b/.github/workflows/validate-gradle-build.yml new file mode 100644 index 00000000..cc6223df --- /dev/null +++ b/.github/workflows/validate-gradle-build.yml @@ -0,0 +1,23 @@ +name: Validate Gradle Wrapper + +on: + push: + branches: + - master-1.12 + - 'feature/**' + pull_request: + branches: + - master-1.12 + +permissions: + contents: read + +jobs: + validation: + name: Validation + runs-on: ubuntu-latest + steps: + - name: Check out source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - name: Validate wrapper integrity + uses: gradle/actions/wrapper-validation@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6 diff --git a/.gitignore b/.gitignore index bc1ca2d0..3f5193ef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,34 +1,72 @@ -# eclipse -bin -*.launch -.settings -.settings/* -.metadata -.classpath -.project +# Eclipse and Buildship +**/bin/ +**/*.launch +**/.settings/ +**/.metadata/ +**/.classpath +**/.project +**/.eclipse/ -# idea -out -*.ipr -*.iws -*.iml -.idea +# IntelliJ IDEA +**/out/ +**/*.ipr +**/*.iws +**/*.iml +**/.idea/ -# gradle -build -.gradle +# Gradle and generated build output +**/build/ +**/.gradle/ +**/classes/ +**/eclipse/ +**/mcmodsrepo/ -# other -eclipse -run -classes +# Minecraft runs, generated worlds, logs, crashes and profiles +**/run/ +**/run-*/ +**/run.*/ +**/run-data/ +**/saves/ +**/world/ +**/logs/ +**/crash-reports/ +**/*.log +**/*.jfr +**/*.hprof +**/hs_err_pid*.log +**/replay_pid*.log -/README.txt -/forge-*-changelog.txt +# Generated validation and test evidence +**/benchmark-*/ +**/regression-*/ +**/evidence/ +**/evidence-*/ +**/*-evidence/ +**/validation.md +**/development.md +**/registry_audit.md +**/registry-audit.md +**/bugreport.md + +# Machine-specific agent context +**/AGENTS.md +**/AGENT.md +**/agent-notes/ +**/.agent/ +**/.agents/ +**/.codex/ +**/.claude/ +**/.gemini/ +**/CLAUDE.md +**/GEMINI.md +**/agent-*.md +**/codex-*.md -secret.json -libs/* -!/libs/README.txt +# Local secrets and scratch dependencies +**/secret.json +**/libs/* +!**/libs/README.txt +/README.txt +/forge-*-changelog.txt .DS_Store -bugreport.md diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index dd5385bb..00000000 --- a/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -language: java -os: linux -dist: trusty -addons: - apt: - update: true - packages: -# - oracle-java8-installer -git: - quiet: true -arch: amd64 -before_cache: - - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ -notifications: - email: false -jdk: - - oraclejdk8 -before_install: skip -install: skip -before_script: - - chmod a+x gradlew -script: - - ./gradlew setupCIWorkspace -S - - ./gradlew clean build -S diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 5ea27611..e92a1888 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,2 +1,16 @@ +Base Metals 2.5.1.112021 + +- Modernized the Minecraft 1.12.2 build on ForgeGradle 7, Gradle 9.6.1 and + checksum-pinned Java and mod dependencies. +- Added deterministic release archives, artifact auditing, Eclipse launch + generation, packaged Forge runtime qualification and guarded GitHub Actions + release delivery. +- Updated the development target to Forge 14.23.5.2859 while preserving Java 8 + game compatibility, registry IDs, OreSpawn 3 behavior and integrations. +- This modernization contains no gameplay or recipe-loop fixes; those changes + will follow separately. + +Base Metals 2.5.0-rc2.332 + 1) (@dshadowwolf) Masses of bug-fixes 2) (@dshadowwolf) Move vanilla extensions out of MMDLib - the lib should be providing anything but raw materials diff --git a/build.gradle b/build.gradle index 1975ed96..d4d8b9a4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,672 +1,1355 @@ -buildscript { - repositories { - jcenter() -// maven { -// url 'http://maven.aliyun.com/nexus/content/groups/public/' -// } -// -// maven { -// url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' -// } - maven { - name = 'forge' - url = 'http://maven.minecraftforge.net/' +import groovy.json.JsonSlurper +import java.nio.charset.StandardCharsets +import java.security.MessageDigest +import java.util.jar.Manifest +import java.util.zip.ZipFile +import org.apache.tools.ant.filters.FixCrLfFilter + +plugins { + id 'java' + id 'eclipse' + id 'idea' + id 'maven-publish' + id 'net.minecraftforge.renamer' version '1.1.5' + id 'net.minecraftforge.gradle' version '7.0.34' +} + +group = project.mod_group +version = project.mod_version +base.archivesName = 'BaseMetals' + +def versionParts = project.mod_version.toString().tokenize('.') +if (versionParts.size() != 4 || !versionParts.every { it ==~ /\d+/ }) { + throw new GradleException("mod_version must use Major.Minor.Bug.Target numeric form: ${project.mod_version}") +} + +def minecraftVersionParts = project.minecraft_version.toString().tokenize('.') +if (minecraftVersionParts.size() < 2 || minecraftVersionParts.size() > 3 + || !minecraftVersionParts.every { it ==~ /\d+/ }) { + throw new GradleException("minecraft_version must use major.minor or major.minor.patch numeric form: " + + project.minecraft_version) +} +def minecraftPatch = minecraftVersionParts.size() == 3 ? minecraftVersionParts[2] : '0' +def expectedTargetVersion = "${minecraftVersionParts[0]}" \ + + "${minecraftVersionParts[1].padLeft(2, '0')}" \ + + "${minecraftPatch.padLeft(2, '0')}" \ + + project.loader_code +if (versionParts[3] != expectedTargetVersion) { + throw new GradleException("mod_version target ${versionParts[3]} does not match " + + "Minecraft ${project.minecraft_version} ${project.loader_name} target ${expectedTargetVersion}") +} + +ext.functional_version = versionParts[0..2].join('.') +ext.display_version = project.mod_version +ext.release_tag = project.mod_version + +def expectedMavenGroup = 'zone.moddev.mc.basemetals' +def expectedMavenArtifact = 'BaseMetals' +def expectedMavenCoordinate = "${expectedMavenGroup}:${expectedMavenArtifact}:${project.version}" + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(8) + vendor = JvmVendorSpec.ADOPTIUM } - maven { - name = 'gradle' - url 'https://plugins.gradle.org/m2/' + withSourcesJar() + withJavadocJar() +} + +tasks.withType(JavaCompile).configureEach { + javaCompiler = javaToolchains.compilerFor { + languageVersion = JavaLanguageVersion.of(8) + vendor = JvmVendorSpec.ADOPTIUM } + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + options.encoding = 'UTF-8' + options.compilerArgs.addAll(['-Xlint:deprecation', '-Xmaxerrs', '1000']) +} + +tasks.named('compileTestJava', JavaCompile) { + options.compilerArgs.add('-proc:none') +} + +tasks.withType(Test).configureEach { + useJUnitPlatform() + workingDir = project.projectDir +} + +tasks.withType(Javadoc).configureEach { + failOnError = false + options.encoding = 'UTF-8' + options.addStringOption('Xdoclint:none', '-quiet') + options.addBooleanOption('notimestamp', true) +} + +tasks.withType(AbstractArchiveTask).configureEach { + preserveFileTimestamps = false + reproducibleFileOrder = true +} + +def archiveTextSuffixes = [ + '.cfg', '.css', '.html', '.info', '.java', '.js', '.json', '.lang', + '.mcmeta', '.md', '.properties', '.txt', '.xml' +] +def archiveTextPatterns = archiveTextSuffixes.collect { "**/*${it}".toString() } +archiveTextPatterns.addAll(['**/element-list', '**/package-list']) +def normalizeArchiveLineEndings = { details -> + details.filter(FixCrLfFilter, + eol: FixCrLfFilter.CrLf.newInstance('lf'), + eof: FixCrLfFilter.AddAsisRemove.newInstance('asis')) +} + +def developmentModOutput = layout.buildDirectory.dir('forge12-development/main') +def prepareDevelopmentMod = tasks.register('prepareDevelopmentMod', Sync) { + group = 'ide' + description = 'Merges production classes and resources for Forge 1.12 development discovery.' + dependsOn tasks.named('classes') + from(tasks.named('compileJava', JavaCompile).flatMap { it.destinationDirectory }) + from(sourceSets.main.output.resourcesDir) + into(developmentModOutput) +} + +minecraft { + mappings channel: project.mappings_channel, version: project.mappings_version + // ForgeGradle launches Mavenizer as a child process, so Gradle's offline + // flag must be forwarded explicitly to prevent network access there too. + if (gradle.startParameter.offline) { + mavenizerArguments.add('--offline') + } + String configuredRunDirectory = providers.gradleProperty('baseMetalsRunDirectory').getOrElse('run') + + runs { + configureEach { + workingDir.convention layout.projectDirectory.dir(configuredRunDirectory) + systemProperty 'forge.logging.console.level', 'debug' + systemProperty 'fml.doNotBackup', 'true' + systemProperty 'fml.queryResult', 'confirm' + systemProperty 'log4j.skipJansi', 'true' + environment 'MC_VERSION', project.minecraft_version + environment 'MOD_CLASSES', developmentModOutput.get().asFile.absolutePath + mods { + basemetals { + source sourceSets.main + } + } + } + register('client') { + if (project.hasProperty('mc_username')) { + args '--username', project.mc_username + } + if (project.hasProperty('mc_uuid')) { + args '--uuid', project.mc_uuid + } + } + register('server') { + args '--nogui' + } + } +} + +tasks.matching { it.name == 'runClient' || it.name == 'runServer' }.configureEach { + dependsOn prepareDevelopmentMod + doFirst { + Set splitProductionOutputs = sourceSets.main.output.files.collect { + it.canonicalFile + } as Set + File mergedOutput = developmentModOutput.get().asFile + setClasspath(project.files( + mergedOutput, + classpath.files.findAll { !splitProductionOutputs.contains(it.canonicalFile) })) + environment 'MC_VERSION', project.minecraft_version + environment 'MOD_CLASSES', mergedOutput.absolutePath + } +} + +repositories { + minecraft.mavenizer(it) + maven fg.forgeMaven + maven fg.minecraftLibsMaven + + if (providers.gradleProperty('legacyDependencyVerificationRepository').isPresent()) { + maven { + name = 'LegacyDependencyVerificationMirror' + url = uri(providers.gradleProperty('legacyDependencyVerificationRepository').get()) + metadataSources { artifact() } + content { includeGroup('curse.maven') } + } + } + + exclusiveContent { + forRepository { + maven { + name = 'Sponge' + url = 'https://repo.spongepowered.org/repository/maven-public' + } + } + filter { includeGroupAndSubgroups('org.spongepowered') } + } + + mavenCentral() maven { - name = 'sonatype' - url = 'https://oss.sonatype.org/content/groups/public' + name = 'MinecraftLibraries' + url = 'https://libraries.minecraft.net/' + } + if (!providers.gradleProperty('legacyDependencyVerificationRepository').isPresent()) { + maven { + name = 'CurseMaven' + url = 'https://www.cursemaven.com' + metadataSources { artifact() } + content { includeGroup('curse.maven') } + } } - } - dependencies { - classpath 'org.junit.platform:junit-platform-gradle-plugin:1.2.+' -// classpath 'com.jaredsburrows:gradle-checker-framework-plugin:0.2.1' - classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: project.fg_version - } } -plugins { -//id 'com.github.spotbugs' version '1.6.2' - id 'com.matthewprenger.cursegradle' version '1.4.0' - id 'org.sonarqube' version '2.8' +def curseCoordinate = { String slug, String projectId, String fileId -> + "curse.maven:${slug}-${projectId}:${fileId}".toString() } -apply plugin: 'net.minecraftforge.gradle.forge' -apply plugin: 'com.matthewprenger.cursegradle' -apply plugin: 'maven-publish' -apply plugin: 'org.sonarqube' -apply plugin: 'org.junit.platform.gradle.plugin' -apply plugin: 'jacoco' -//apply plugin: 'com.github.spotbugs' -//apply plugin: 'com.jaredsburrows.checkerframework' +def dependencySpecs = [ + mmdlib: [ + coordinate: curseCoordinate('mmdlib', project.mmdlib_curse_project_id, project.mmdlib_curse_file_id), + version: project.mmdlib_version, sha256: project.mmdlib_sha256, required: true + ], + orespawn3: [ + coordinate: curseCoordinate('mmd-orespawn', project.orespawn3_curse_project_id, project.orespawn3_curse_file_id), + version: project.orespawn3_version, sha256: project.orespawn3_sha256, required: true + ], + alt: [ + coordinate: curseCoordinate('additional-loot-tables', project.alt_curse_project_id, project.alt_curse_file_id), + version: project.alt_version, sha256: project.alt_sha256, required: false + ], + mantle: [ + coordinate: curseCoordinate('mantle', project.mantle_curse_project_id, project.mantle_curse_file_id), + version: project.mantle_version, sha256: project.mantle_sha256, required: false + ], + tconstruct: [ + coordinate: curseCoordinate('tinkers-construct', project.tconstruct_curse_project_id, project.tconstruct_curse_file_id), + version: project.tconstruct_version, sha256: project.tconstruct_sha256, required: false + ], + conarm: [ + coordinate: curseCoordinate('constructs-armory', project.conarm_curse_project_id, project.conarm_curse_file_id), + version: project.conarm_version, sha256: project.conarm_sha256, required: false + ], + thaumcraft: [ + coordinate: curseCoordinate('thaumcraft', project.thaumcraft_curse_project_id, project.thaumcraft_curse_file_id), + version: project.thaumcraft_version, sha256: project.thaumcraft_sha256, required: false + ], + baubles: [ + coordinate: curseCoordinate('baubles', project.baubles_curse_project_id, project.baubles_curse_file_id), + version: project.baubles_version, sha256: project.baubles_sha256, required: false + ], + cofhcore: [ + coordinate: curseCoordinate('cofh-core', project.cofhcore_curse_project_id, project.cofhcore_curse_file_id), + version: project.cofhcore_version, sha256: project.cofhcore_sha256, required: false + ] +] + +configurations { + orespawn3Development { + canBeConsumed = false + canBeResolved = true + transitive = false + } + legacyDependencyArtifacts { + canBeConsumed = false + canBeResolved = true + transitive = false + } + legacyBaselineArtifact { + canBeConsumed = false + canBeResolved = true + transitive = false + } + orespawn4CompatibilityArtifact { + canBeConsumed = false + canBeResolved = true + transitive = false + } +} -repositories { - mavenLocal() - mavenCentral() +def mmdlibDevelopmentDependency = renamer.dependency(dependencySpecs.mmdlib.coordinate) +def orespawn3DevelopmentDependency = renamer.dependency(dependencySpecs.orespawn3.coordinate) + +def sanitizedOrespawn3DevelopmentJar = tasks.register('sanitizedOrespawn3DevelopmentJar', Jar) { + group = 'ide' + description = 'Removes stale release signatures from the MCP-remapped OreSpawn 3 development jar.' + inputs.files(configurations.orespawn3Development) + archiveFileName = "OreSpawn-${project.orespawn3_version}-development.jar" + destinationDirectory = layout.buildDirectory.dir('development-dependencies') + includeEmptyDirs = false + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + from({ + configurations.orespawn3Development.files.collect { dependency -> zipTree(dependency) } + }) { + exclude 'META-INF/MANIFEST.MF' + exclude 'META-INF/*.SF' + exclude 'META-INF/*.RSA' + exclude 'META-INF/*.DSA' + } } dependencies { - testCompile('org.junit.jupiter:junit-jupiter-api:5.2.+') - testCompile('org.junit.platform:junit-platform-launcher:1.2.+') - testRuntime('org.junit.jupiter:junit-jupiter-engine:5.2.+') - testCompile('org.mockito:mockito-core:2.+') + implementation minecraft.dependency( + "net.minecraftforge:forge:${project.minecraft_version}-${project.forge_version}") + compileOnly 'org.lwjgl.lwjgl:lwjgl_util:2.9.4-nightly-20150209' + + implementation mmdlibDevelopmentDependency + orespawn3Development orespawn3DevelopmentDependency + compileOnly files(sanitizedOrespawn3DevelopmentJar.flatMap { it.archiveFile }) + runtimeOnly files(sanitizedOrespawn3DevelopmentJar.flatMap { it.archiveFile }) + + compileOnly renamer.dependency(dependencySpecs.alt.coordinate) + compileOnly renamer.dependency(dependencySpecs.mantle.coordinate) + compileOnly renamer.dependency(dependencySpecs.tconstruct.coordinate) + compileOnly renamer.dependency(dependencySpecs.conarm.coordinate) + compileOnly renamer.dependency(dependencySpecs.thaumcraft.coordinate) + compileOnly renamer.dependency(dependencySpecs.baubles.coordinate) + compileOnly renamer.dependency(dependencySpecs.cofhcore.coordinate) + + dependencySpecs.each { name, spec -> + legacyDependencyArtifacts spec.coordinate + } + legacyBaselineArtifact curseCoordinate('base-metals', + project.legacy_basemetals_curse_project_id, + project.legacy_basemetals_curse_file_id) + orespawn4CompatibilityArtifact curseCoordinate('mmd-orespawn', + project.orespawn4_curse_project_id, + project.orespawn4_curse_file_id) + + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.2' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.10.2' + testImplementation 'org.mockito:mockito-core:2.28.2' } -project.afterEvaluate { - def junitPlatformTestTask = project.tasks.getByName('junitPlatformTest') +// Renamer Gradle replaces ForgeGradle's retired deobfProvided configuration. +// Dependencies are mapped from their production SRG names to stable_39 for the +// development compile/runtime classpaths; the public jar is mapped back below. +renamer.mappings.from minecraft.dependency.toSrgFile - // configure jacoco to analyze the junitPlatformTest task - jacoco { - // this tool version is compatible with - toolVersion = '0.8.1' - applyTo junitPlatformTestTask - } +tasks.named('processResources', ProcessResources) { + filteringCharset = 'UTF-8' + inputs.property('version', project.mod_version) + inputs.property('mcversion', project.minecraft_version) - // create junit platform jacoco task - project.task(type: JacocoReport, "junitPlatformJacocoReport", - { - sourceDirectories = files("./src/main") - classDirectories = files("$buildDir/classes/main") - executionData junitPlatformTestTask - }) + filesMatching('mcmod.info') { + expand version: project.mod_version, mcversion: project.minecraft_version + } + rename '(.+_at.cfg)', 'META-INF/$1' + filesMatching(archiveTextPatterns, normalizeArchiveLineEndings) } -junitPlatform { - // platformVersion '1.2.0' - // logManager 'org.apache.logging.log4j.jul.LogManager' - reportsDir file("${project.buildDir}/test-results/junit-platform") - // enableStandardTestTask true - // selectors (optional) - // filters (optional) +tasks.named('jar', Jar) { + archiveClassifier = 'deobf' + destinationDirectory = layout.buildDirectory.dir('libs-dev') + includeEmptyDirs = false + manifest { + attributes([ + 'Maven-Artifact' : expectedMavenCoordinate, + 'Implementation-Title' : base.archivesName.get(), + 'Implementation-Version': project.version, + 'Built-On-Java' : '8', + 'Built-On' : "${project.minecraft_version}-${project.forge_version}" + ]) + } } -/* -spotbugs { - toolVersion = '3.1.5' +def releaseJar = renamer.classes(tasks.named('jar', Jar)) { + map.from minecraft.dependency.toSrgFile + archiveClassifier = null } -*/ -tasks.withType(JavaCompile) { - options.encoding = 'UTF-8' - options.compilerArgs = [ - '-Xlint:deprecation', // deprecation, rawtypes, cast, unchecked, all -// '-Xdiags:verbose', -// '-Werror' - ] +tasks.named('sourcesJar', Jar) { + filteringCharset = 'UTF-8' + includeEmptyDirs = false + archiveClassifier = 'sources' + filesMatching(archiveTextPatterns, normalizeArchiveLineEndings) + manifest { + attributes([ + 'Maven-Artifact' : "${expectedMavenCoordinate}:sources", + 'Implementation-Title' : "${base.archivesName.get()}-sources", + 'Implementation-Version': project.version + ]) + } +} + +tasks.named('javadocJar', Jar) { + filteringCharset = 'UTF-8' + archiveClassifier = 'javadoc' + filesMatching('**/*.html') { + filter { line -> line.replaceFirst(/^ +(?=[^<].* .*(?:,|\)<\/pre>)$)/, ' ') } + } + filesMatching(archiveTextPatterns, normalizeArchiveLineEndings) + manifest { + attributes([ + 'Maven-Artifact' : "${expectedMavenCoordinate}:javadoc", + 'Implementation-Title' : "${base.archivesName.get()}-javadoc", + 'Implementation-Version': project.version + ]) + } } -javadoc { - failOnError = false +['apiElements', 'runtimeElements'].each { configurationName -> + configurations.named(configurationName) { + artifacts.clear() + } + artifacts { + add(configurationName, releaseJar) + } } -test { -// useJUnitPlatform() -/* - useJUnitPlatform { - includeTags 'fast', 'smoke & feature-a' - // excludeTags 'slow', 'ci' - includeEngines 'junit-jupiter' - // excludeEngines 'junit-vintage' - } -*/ +tasks.named('assemble') { + dependsOn releaseJar + dependsOn tasks.named('sourcesJar') + dependsOn tasks.named('javadocJar') } -def mod_file = getModFile() -def short_version = getVersion('VERSION', mod_file) -version = mc_version + '-' + short_version -def display_version = short_version +def java8Launcher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(8) + vendor = JvmVendorSpec.ADOPTIUM +} -if (System.getenv().BUILD_NUMBER) { - version += '.' + System.getenv().BUILD_NUMBER - display_version += '.' + System.getenv().BUILD_NUMBER +def java25Launcher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(25) + vendor = JvmVendorSpec.ADOPTIUM } -sourceCompatibility = targetCompatibility = '1.8' +tasks.register('verifyReleaseToolchains') { + group = 'verification' + description = 'Requires the pinned Gradle, Mavenizer, compilation, and runtime JDKs.' + doLast { + String gradleVendor = System.getProperty('java.vendor') + String gradleRuntime = System.getProperty('java.runtime.version') + if (project.gradle_java_version != '17' + || gradleVendor != 'Eclipse Adoptium' + || gradleRuntime != '17.0.1+12') { + throw new GradleException("Expected Gradle on Temurin 17.0.1+12, found " + + "${gradleVendor} ${gradleRuntime} at ${System.getProperty('java.home')}") + } + + def metadata = java8Launcher.get().metadata + if (project.java_toolchain_version != '8.0.502+7' + || metadata.vendor.toString() != 'Eclipse Temurin' + || metadata.javaRuntimeVersion != '1.8.0_502-b07') { + throw new GradleException("Expected Temurin ${project.java_toolchain_version}, found " + + "${metadata.vendor} ${metadata.javaRuntimeVersion} at ${metadata.installationPath}") + } -eclipse.project { - buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder' - natures 'org.eclipse.buildship.core.gradleprojectnature' + def mavenizerMetadata = java25Launcher.get().metadata + if (project.mavenizer_java_version != '25.0.3+9' + || mavenizerMetadata.vendor.toString() != 'Eclipse Temurin' + || mavenizerMetadata.javaRuntimeVersion != '25.0.3+9-LTS') { + throw new GradleException("Expected Mavenizer on Temurin ${project.mavenizer_java_version}, found " + + "${mavenizerMetadata.vendor} ${mavenizerMetadata.javaRuntimeVersion} " + + "at ${mavenizerMetadata.installationPath}") + } + } } -class Secrets { - def data = null +tasks.named('check') { + dependsOn tasks.named('verifyReleaseToolchains') +} - def getProperty(String key) { - return data ? data[key] : '' - } +def expectedReleaseFiles = providers.provider { + def prefix = "${base.archivesName.get()}-${project.version}" + [ + "${prefix}.jar", + "${prefix}-sources.jar", + "${prefix}-javadoc.jar" + ] +} +def preparedReleaseDir = providers.gradleProperty('preparedReleaseDir') + +def sha256 = { File candidate -> + MessageDigest digest = MessageDigest.getInstance('SHA-256') + candidate.withInputStream { input -> + byte[] buffer = new byte[8192] + for (int read = input.read(buffer); read >= 0; read = input.read(buffer)) { + if (read > 0) digest.update(buffer, 0, read) + } + } + digest.digest().encodeHex().toString().toUpperCase() } -import groovy.json.JsonSlurper +tasks.register('verifyReleaseConfiguration') { + group = 'verification' + description = 'Validates the complete Base Metals 1.12 release identity and dependency contract.' + dependsOn tasks.named('verifyReleaseToolchains') + doLast { + if (project.mod_version != '2.5.1.112021' + || project.minecraft_version != '1.12.2' + || project.forge_version != '14.23.5.2859' + || project.mappings_channel != 'stable' + || project.mappings_version != '39-1.12') { + throw new GradleException('Unexpected Base Metals version, Minecraft, Forge, or mappings target') + } + String buildScript = file('build.gradle').getText('UTF-8') + String settingsScript = file('settings.gradle').getText('UTF-8') + Properties wrapper = new Properties() + file('gradle/wrapper/gradle-wrapper.properties').withInputStream { wrapper.load(it) } + if (!buildScript.contains("id 'net.minecraftforge.gradle' version '7.0.34'") + || !buildScript.contains("id 'net.minecraftforge.renamer' version '1.1.5'") + || !settingsScript.contains("version '1.0.0'") + || wrapper.getProperty('distributionUrl') + != 'https://services.gradle.org/distributions/gradle-9.6.1-bin.zip' + || wrapper.getProperty('distributionSha256Sum') + != '9c0f7faeeb306cb14e4279a3e084ca6b596894089a0638e68a07c945a32c9e14') { + throw new GradleException('ForgeGradle, Renamer, Foojay, or Gradle wrapper identity drifted') + } + if (project.loader_name != 'forge' || project.loader_code != '1' + || project.java_version != '8' + || project.java_toolchain_version != '8.0.502+7' + || project.gradle_java_version != '17' + || project.mavenizer_java_version != '25.0.3+9') { + throw new GradleException('Unexpected loader or Java release metadata') + } + if (project.mod_group != expectedMavenGroup + || base.archivesName.get() != expectedMavenArtifact + || "${project.group}:${base.archivesName.get()}:${project.version}" != expectedMavenCoordinate) { + throw new GradleException("Unexpected Maven coordinate; expected ${expectedMavenCoordinate}") + } + if (project.cf_project_id != '240967' + || project.cf_requirements != 'mmd-orespawn,mmdlib' + || project.cf_versions != '1.12.2') { + throw new GradleException('Unexpected CurseForge publication contract') + } + if (dependencySpecs.mmdlib.version != '1.0.0-rc2.36' + || dependencySpecs.orespawn3.version != '3.3.1.179') { + throw new GradleException('Unexpected primary MMDLib or OreSpawn 3 version') + } + String source = file('src/main/java/com/mcmoddev/basemetals/BaseMetals.java').getText('UTF-8') + if (!source.contains('VERSION = "2.5.1.112021"') + || !source.contains('certificateFingerprint = ""')) { + throw new GradleException('Base Metals source version or unsigned fingerprint contract drifted') + } + } +} -def secretFile -if (System.getenv().SECRET_FILE) { - secretFile = file System.getenv().SECRET_FILE -} else { - secretFile = file 'secret.json' +tasks.register('verifyReleaseDependencies') { + group = 'verification' + description = 'Resolves and checksum-verifies all exact legacy mod dependencies.' + dependsOn tasks.named('verifyReleaseConfiguration') + doLast { + def resolved = configurations.legacyDependencyArtifacts.resolvedConfiguration.resolvedArtifacts + if (resolved.size() != dependencySpecs.size()) { + throw new GradleException("Expected ${dependencySpecs.size()} exact legacy artifacts, found ${resolved.size()}") + } + dependencySpecs.each { name, spec -> + def bits = spec.coordinate.split(':') + def matches = resolved.findAll { + it.moduleVersion.id.group == bits[0] + && it.moduleVersion.id.name == bits[1] + && it.moduleVersion.id.version == bits[2] + } + if (matches.size() != 1) { + throw new GradleException("Expected exactly ${spec.coordinate}, found ${matches*.moduleVersion*.id}") + } + String actual = sha256(matches.first().file) + if (actual != spec.sha256) { + throw new GradleException("${name} SHA-256 is ${actual}, expected ${spec.sha256}") + } + } + def orespawn4 = configurations.orespawn4CompatibilityArtifact + .resolvedConfiguration.resolvedArtifacts + if (orespawn4.size() != 1 + || sha256(orespawn4.first().file) != project.orespawn4_sha256) { + throw new GradleException('OreSpawn 4 compatibility artifact is missing or has the wrong SHA-256') + } + ZipFile compatibilityJar = new ZipFile(orespawn4.first().file) + try { + def entry = compatibilityJar.getEntry('mcmod.info') + def metadata = entry == null ? null : new JsonSlurper().parseText( + compatibilityJar.getInputStream(entry).getText(StandardCharsets.UTF_8.name())) + def mod = metadata instanceof List ? metadata.find { it.modid == 'orespawn' } : metadata + if (mod == null || mod.version != project.orespawn4_version) { + throw new GradleException("OreSpawn 4 compatibility artifact is not ${project.orespawn4_version}") + } + } finally { + compatibilityJar.close() + } + } } -project.ext.secret = new Secrets() -if (secretFile.exists()) { - secretFile.withReader { - project.ext.secret.data = new JsonSlurper().parse it - } +tasks.register('verifyJsonResources') { + group = 'verification' + description = 'Parses every production JSON resource.' + inputs.files(fileTree('src/main/resources') { include '**/*.json' }) + doLast { + fileTree('src/main/resources') { include '**/*.json' }.files.sort().each { candidate -> + try { + new JsonSlurper().parse(candidate) + } catch (Exception failure) { + throw new GradleException("Invalid JSON resource ${project.relativePath(candidate)}", failure) + } + } + } } -minecraft { - version = project.forge_mc_version + '-' + project.forge_version - runDir = 'run' - mappings = project.mcp_mappings +tasks.named('check') { + dependsOn tasks.named('verifyReleaseConfiguration') + dependsOn tasks.named('verifyReleaseDependencies') + dependsOn tasks.named('verifyJsonResources') +} - if (project.hasProperty('signSHA1')) { - replace '@FINGERPRINT@', project.findProperty('signSHA1') - } else { - replace '@FINGERPRINT@', '' - } +tasks.register('verifyHistoricalOreSpawnConfiguration') { + group = 'verification' + description = 'Locks the eleven-rule OreSpawn 3 data contract and fallback hand-off behavior.' + inputs.file('src/main/resources/assets/basemetals/orespawn/basemetals.json') + inputs.file('src/main/java/com/mcmoddev/basemetals/integration/orespawn/BaseMetalsOreSpawn.java') + doLast { + def config = new JsonSlurper().parse( + file('src/main/resources/assets/basemetals/orespawn/basemetals.json')) + List expectedRules = [ + 'coldiron_ore', 'adamantine_ore', 'starsteel_ore', 'copper_ore', + 'silver_ore', 'tin_ore', 'lead_ore', 'zinc_ore', 'mercury_ore', + 'nickel_ore', 'platinum_ore' + ].sort() + if (config.version != '2.0' || config.spawns.keySet().sort() != expectedRules) { + throw new GradleException('The packaged OreSpawn 3 configuration is not the eleven-rule legacy contract') + } + config.spawns.each { name, rule -> + if (!rule.enabled || rule.retrogen || rule.blocks.size() != 1 + || rule.blocks.first().name != "basemetals:${name}") { + throw new GradleException("Historical OreSpawn rule ${name} changed shape") + } + } + String plugin = file('src/main/java/com/mcmoddev/basemetals/integration/orespawn/BaseMetalsOreSpawn.java') + .getText('UTF-8') + if (!plugin.contains('@OreSpawnPlugin(modid = BaseMetals.MODID') + || !plugin.contains('resourcePath = SharedStrings.ORESPAWN_MODID') + || plugin.contains('package com.mcmoddev.orespawn;')) { + throw new GradleException('The OreSpawn 3 plugin discovery contract changed') + } + } +} - if (project.hasProperty('coreplugin')) { - clientJvmArgs += '-Dfml.coreMods.load=' + project.coreplugin - serverJvmArgs += '-Dfml.coreMods.load=' + project.coreplugin - } +tasks.named('check') { + dependsOn tasks.named('verifyHistoricalOreSpawnConfiguration') +} - if (project.hasProperty('mc_username')) { - clientRunArgs += ['--username', project.mc_username] - if (project.hasProperty('mc_password')) { - clientRunArgs += ['--password', project.mc_password] +tasks.register('verifyReleaseArtifacts') { + group = 'verification' + description = 'Audits deterministic jars, legacy inventory, bytecode, metadata, and package isolation.' + dependsOn tasks.named('assemble') + dependsOn tasks.named('verifyReleaseDependencies') + doLast { + File libs = layout.buildDirectory.dir('libs').get().asFile + List expected = expectedReleaseFiles.get().sort() + List jars = (libs.listFiles() ?: [] as File[]) + .findAll { it.name.endsWith('.jar') } + .sort { it.name } + if (jars.collect { it.name } != expected || jars.any { it.length() == 0L }) { + throw new GradleException("Release directory must contain exactly ${expected}; found ${jars*.name}") + } + + File mainJar = new File(libs, "BaseMetals-${project.version}.jar") + ZipFile zip = new ZipFile(mainJar) + try { + List names = zip.entries().collect { it.name } + List forbiddenNames = names.findAll { name -> + name.startsWith('com/mcmoddev/lib/') + || name.startsWith('net/minecraft/') + || name.startsWith('net/minecraftforge/') + || name.startsWith('org/junit/') + || name.contains('/test/') + || name.toLowerCase().contains('fixture') + || name.toLowerCase().contains('agent') + || name.toLowerCase().contains('runtimeprobe') + } + if (!forbiddenNames.isEmpty()) { + throw new GradleException("Release jar contains forbidden entries: ${forbiddenNames.take(20)}") + } + + zip.entries().findAll { it.name.endsWith('.class') }.each { entry -> + byte[] header = new byte[8] + zip.getInputStream(entry).withCloseable { input -> + if (input.read(header) != header.length) { + throw new GradleException("Cannot inspect bytecode header for ${entry.name}") + } + } + int major = ((header[6] & 0xff) << 8) | (header[7] & 0xff) + if (major != 52) { + throw new GradleException("${entry.name} uses Java class major ${major}, expected 52") + } + } + + def manifestEntry = zip.getEntry('META-INF/MANIFEST.MF') + def manifest = manifestEntry == null ? null + : new Manifest(zip.getInputStream(manifestEntry)).mainAttributes + if (manifest == null + || manifest.getValue('Maven-Artifact') != expectedMavenCoordinate + || manifest.getValue('Implementation-Version') != project.mod_version + || manifest.getValue('Timestamp') != null + || manifest.getValue('Built-On') != '1.12.2-14.23.5.2859') { + throw new GradleException('Release manifest identity is incomplete or volatile') + } + + def metadataEntry = zip.getEntry('mcmod.info') + if (metadataEntry == null) { + throw new GradleException('Release jar is missing mcmod.info') + } + def metadata = new JsonSlurper().parseText( + zip.getInputStream(metadataEntry).getText(StandardCharsets.UTF_8.name())) + def mod = metadata instanceof List ? metadata.find { it.modid == 'basemetals' } : metadata + if (mod == null || mod.version != project.mod_version || mod.mcversion != project.minecraft_version) { + throw new GradleException('Packaged mcmod.info has the wrong mod or target version') + } + + List leakedPaths = [] + zip.entries().findAll { entry -> archiveTextSuffixes.any { entry.name.endsWith(it) } }.each { entry -> + String text = zip.getInputStream(entry).getText(StandardCharsets.UTF_8.name()) + if (text =~ /(?i)([A-Z]:\\Users\\|[A-Z]:\\BaseMetals|\/home\/runner\/|\/Users\/)/) { + leakedPaths.add(entry.name) + } + } + if (!leakedPaths.isEmpty()) { + throw new GradleException("Release jar leaks local paths in ${leakedPaths}") + } + } finally { + zip.close() + } + + def baselineArtifacts = configurations.legacyBaselineArtifact.resolvedConfiguration.resolvedArtifacts + if (baselineArtifacts.size() != 1) { + throw new GradleException("Expected one released Base Metals baseline, found ${baselineArtifacts.size()}") + } + File baseline = baselineArtifacts.first().file + String baselineHash = sha256(baseline) + if (baselineHash != project.legacy_basemetals_sha256) { + throw new GradleException("Released baseline SHA-256 is ${baselineHash}, expected " + + project.legacy_basemetals_sha256) + } + def entryInventory = { File jarFile -> + ZipFile candidate = new ZipFile(jarFile) + try { + candidate.entries().findAll { !it.isDirectory() }.collect { it.name }.sort() + } finally { + candidate.close() + } + } + List currentInventory = entryInventory(mainJar) + List legacyInventory = entryInventory(baseline) + List allowedAddedEntries = [ + 'assets/mmdlib/lang/en_us.lang', + 'assets/mmdlib/lang/es_es.lang', + // Avoid Java's package-signer collision with signed OreSpawn + // while preserving the plugin annotation and resource path. + 'com/mcmoddev/basemetals/integration/orespawn/BaseMetalsOreSpawn.class' + ] + List allowedRemovedEntries = [ + // The historical CurseForge jar was signed and carried FML's + // generated cache. Neither belongs in a reproducible rebuild. + 'META-INF/MINECRAF.RSA', + 'META-INF/MINECRAF.SF', + 'META-INF/fml_cache_annotation.json', + 'META-INF/fml_cache_class_versions.json', + 'com/mcmoddev/orespawn/BaseMetalsOreSpawn.class', + // These source files were deliberately removed on master-1.12 + // after 2.5.0-rc2.332; the modernization does not resurrect them. + 'com/mcmoddev/basemetals/items/MMDToolEffects.class', + 'com/mcmoddev/basemetals/items/package-info.class' + ] + List unexpectedAdded = (currentInventory - legacyInventory) - allowedAddedEntries + List unexpectedRemoved = (legacyInventory - currentInventory) - allowedRemovedEntries + if (!unexpectedAdded.isEmpty() || !unexpectedRemoved.isEmpty() + || !allowedAddedEntries.every { currentInventory.contains(it) } + || !allowedRemovedEntries.every { legacyInventory.contains(it) }) { + throw new GradleException("Release inventory drifted from ${project.legacy_basemetals_version}; " + + "added=${unexpectedAdded.take(20)}, removed=${unexpectedRemoved.take(20)}") + } } - } - if (project.hasProperty('mc_uuid')) { - clientRunArgs += ['--uuid', project.mc_uuid] - } +} - // disable server gui - serverRunArgs += 'nogui' +tasks.register('writeReleaseChecksums') { + group = 'verification' + description = 'Writes SHA-256 checksums for the audited release jars.' + dependsOn tasks.named('verifyReleaseArtifacts') + def outputFile = layout.buildDirectory.file('release/SHA256SUMS') + inputs.files(providers.provider { + expectedReleaseFiles.get().collect { name -> + layout.buildDirectory.file("libs/${name}").get().asFile + } + }) + outputs.file(outputFile) + doLast { + File output = outputFile.get().asFile + output.parentFile.mkdirs() + File libs = layout.buildDirectory.dir('libs').get().asFile + String contents = expectedReleaseFiles.get().sort().collect { name -> + "${sha256(new File(libs, name))} ${name}" + }.join(System.lineSeparator()) + System.lineSeparator() + output.setText(contents, 'UTF-8') + } +} - // skip the screen to confirm that you want to load a world with missing registry entries - serverJvmArgs += '-Dfml.doNotBackup=true' - clientJvmArgs += '-Dfml.doNotBackup=true' +tasks.register('verifyPreparedReleaseArtifacts') { + group = 'verification' + description = 'Audits a previously built immutable release bundle before publication.' + doLast { + if (!preparedReleaseDir.isPresent()) { + throw new GradleException('preparedReleaseDir is required for prepared artifact publication') + } + File prepared = file(preparedReleaseDir.get()) + List expected = expectedReleaseFiles.get().sort() + List jars = (prepared.listFiles() ?: [] as File[]) + .findAll { it.name.endsWith('.jar') }.sort { it.name } + if (jars.collect { it.name } != expected || jars.any { it.length() == 0L }) { + throw new GradleException("Prepared release must contain exactly ${expected}") + } + File checksums = new File(prepared, 'SHA256SUMS') + File changelog = new File(prepared, 'CHANGELOG.txt') + if (!checksums.isFile() || !changelog.isFile()) { + throw new GradleException('Prepared release is missing SHA256SUMS or CHANGELOG.txt') + } + List actual = jars.collect { "${sha256(it)} ${it.name}" }.sort() + List declared = checksums.readLines('UTF-8').findAll { !it.trim().isEmpty() }.sort() + if (actual != declared) { + throw new GradleException('Prepared release checksums do not match the immutable jars') + } + } +} - // skip having to confirm on server - serverJvmArgs += '-Dfml.queryResult=confirm' +tasks.register('runtimeProbeJar', Jar) { + group = 'verification' + description = 'Builds the mapped test-only packaged-runtime acceptance probe.' + dependsOn tasks.named('testClasses') + archiveBaseName = 'basemetals-runtime-probe' + archiveVersion = '' + archiveClassifier = 'deobf' + destinationDirectory = layout.buildDirectory.dir('runtime-probes-dev') + from(sourceSets.test.output) { + include 'com/mcmoddev/basemetals/test/BaseMetalsRuntimeProbe*.class' + } +} - //skip jansi warnings in the log - serverJvmArgs += '-Dlog4j.skipJansi=true' - clientJvmArgs += '-Dlog4j.skipJansi=true' +def packagedRuntimeProbeJar = renamer.classes(tasks.named('runtimeProbeJar', Jar)) { + map.from minecraft.dependency.toSrgFile + archiveClassifier = null + output = layout.buildDirectory.file('runtime-probes/basemetals-runtime-probe.jar') +} - if (project.hasProperty('client_args')) { - clientJvmArgs += project.client_args - } - if (project.hasProperty('server_args')) { - serverJvmArgs += project.server_args - } +tasks.register('packagedRuntimeProbes') { + group = 'verification' + dependsOn packagedRuntimeProbeJar } -repositories { - mavenLocal() - - maven { // Mantle, TCon, JEI - name 'DVS1 Maven FS' - url 'http://dvs1.progwml6.com/files/maven/' - } - maven { // CCL, CCC, NEI - name 'Chickenbones Repo' - url 'http://chickenbones.net/maven/' - } - maven { // The One Probe, EnderIO, EnderCore - name 'tterrag' - url 'http://maven.tterrag.com/' - } - maven { // Tesla - name 'MMD' - url 'https://maven.mcmoddev.com/' - } - maven { // MCMultipart - name 'amadornes' - url 'http://maven.amadornes.com/' - } - maven { // CraftTweaker, ZenScript - name 'blamejared' - url 'http://maven.blamejared.com/' - } - maven { // IC2 - name 'industrialcraft' - url 'http://maven.ic2.player.to/' - } -/* maven { // HWYLA - name 'tehnut' - url 'http://tehnut.info/maven/' - }*/ - maven { // CoFH - name 'Covers Maven' - url 'http://maven.covers1624.net/' - } - maven { - name = 'CurseForge' - url = 'https://minecraft.curseforge.com/api/maven/' - } - maven { - name 'opencomputers' - url 'http://maven.cil.li/' - } - maven { // Mekanism, TAIGA - name 'jitpack' - url 'https://jitpack.io/' - } - maven { // Buildcraft - name 'buildcraft' - url 'https://mod-buildcraft.com/maven/' - } - maven { // Storage Drawers - name 'thiakil' - url 'http://maven.thiakil.com/' - } - maven { // Applied Energistics - name 'forge' - url 'https://maven.minecraftforge.net/' - } - /* - ivy { - url 'http://ae-mod.info/builds' - layout "pattern", { - artifact "[module]-[revision](-[classifier])(.[ext])" - } - } - */ +def packagedForgeRuntimeRoot = providers.gradleProperty('packagedForgeRuntimeRoot') +def validatePackagedForgeRoot = { + if (!packagedForgeRuntimeRoot.isPresent()) { + throw new GradleException('packagedForgeRuntimeRoot is required for packaged Forge qualification') + } + File root = file(packagedForgeRuntimeRoot.get()) + [ + new File(root, "forge-${project.minecraft_version}-${project.forge_version}-universal.jar"), + new File(root, "minecraft_server.${project.minecraft_version}.jar"), + new File(root, 'libraries') + ].each { required -> + if (!required.exists()) { + throw new GradleException("Packaged Forge runtime is missing ${required}") + } + } + root } -dependencies { - deobfProvided "com.mcmoddev:AdditionalLootTables:${mc_version}-${alt_version}" - //runtime "com.mcmoddev:AdditionalLootTables:${mc_version}-${alt_version}" - deobfProvided "com.mcmoddev:OreSpawn:${mc_version}-${orespawn_version}" - //runtime "com.mcmoddev:OreSpawn:${mc_version}-${orespawn_version}" - - // TODO: We don't use this - deobfProvided "net.darkhax.tesla:Tesla-${mc_version}.2:${tesla_version}" -//runtime "net.darkhax.tesla:Tesla-${mc_version}.2:${tesla_version}" - - deobfProvided ("com.github.aidancbrady:Mekanism:${mekanism_version}") { - exclude group: 'com.mod-buildcraft' - exclude group: 'CraftTweaker2' - exclude group: 'MCMultiPart2' - exclude group: 'cofh' - exclude group: 'com.blamejared' - exclude group: 'mezz.jei' - exclude group: 'net.darkhax.tesla' - exclude module: 'CTM' - exclude module: 'Hwyla' - exclude module: 'InventoryTweaks' - exclude module: 'industrialcraft-2' - exclude module: 'OpenComputers' - } - /* - runtime ("com.github.aidancbrady:Mekanism:${mekanism_version}") { - exclude group: 'com.mod-buildcraft' - exclude group: 'CraftTweaker2' - exclude group: 'MCMultiPart2' - exclude group: 'cofh' - exclude group: 'com.blamejared' - exclude group: 'mezz.jei' - exclude group: 'net.darkhax.tesla' - exclude module: 'CTM' - exclude module: 'Hwyla' - exclude module: 'InventoryTweaks' - exclude module: 'industrialcraft-2' - exclude module: 'OpenComputers' - } - */ - - // TODO: We don't use this - deobfProvided ("slimeknights.mantle:Mantle:${mc_version}-${mantle_version}") { - exclude group: 'mezz.jei' - } - -// runtime ("slimeknights.mantle:Mantle:${mc_version}-${mantle_version}") { -// exclude group: 'mezz.jei' -// } - - - deobfProvided ("slimeknights:TConstruct:${mc_version}.2-${tconstruct_version}") { - exclude group: 'mezz.jei' - } - -// runtime ("slimeknights:TConstruct:${mc_version}-${tconstruct_version}") { -// exclude group: 'mezz.jei' -// } - - deobfProvided ("constructs-armory:conarm:${mc_version}.2:${conarm_version}") { - exclude group: 'mezz.jei' - } - -// runtime ("slimeknights:TConstruct:${mc_version}-${conarm_version}") { -// exclude group: 'mezz.jei' -// } - - - deobfProvided "mezz.jei:jei_${mc_version}.2:${jei_version}" -// runtime "mezz.jei:jei_${mc_version}:${jei_version}" - - // TODO: We don't use this - deobfProvided "codechicken:CodeChickenLib:${mc_version}.2-${ccl_version}:universal" -//runtime "codechicken:CodeChickenLib:${mc_version}-${ccl_version}:universal" - - deobfProvided ("codechicken:NotEnoughItems:${mc_version}.2-${nei_version}:universal") { - exclude group: 'codechicken' - exclude group: 'mezz.jei' - } - /* - runtime ("codechicken:NotEnoughItems:${mc_version}-${nei_version}:universal") { - exclude group: 'codechicken' - exclude group: 'mezz.jei' - } - */ - - // TODO: We don't use this - deobfProvided "MCMultiPart2:MCMultiPart:${mcmp_version}" -//runtime "MCMultiPart2:MCMultiPart:${mcmp_version}" -//deobfProvided "MCMultiPart2:MCMultiPart-exp:${mcmp_experimental_version}" -//runtime "MCMultiPart2:MCMultiPart-exp:${mcmp_experimental_version}" - - deobfProvided ("mcjty.theoneprobe:TheOneProbe-${mc_version}:${mc_version}-${top_version}:api") { - exclude group: 'cofh' - } - /* - runtime ("mcjty.theoneprobe:TheOneProbe-${mc_version}:${mc_version}-${top_version}") { - exclude group: 'cofh' - } - */ - - deobfProvided "portablejim:VeinMiner:${veinminer_version}" -//runtime "portablejim:VeinMiner:${veinminer_version}" - - deobfProvided ("net.industrial-craft:industrialcraft-2:${ic2_version}:api") { - exclude group: 'mezz.jei' - } -//runtime "net.industrial-craft:industrialcraft-2:${ic2_version}" - - // TODO: We don't use this -//deobfProvided "com.googlecode.efficient-java-matrix-library:ejml:0.23" -//runtime "com.googlecode.efficient-java-matrix-library:ejml:0.23" - - deobfProvided "CraftTweaker2:CraftTweaker2-API:${ct_api_version}" - deobfProvided "CraftTweaker2:CraftTweaker2-MC1120-Main:${mc_version}-${ct_version}" - - // TODO: We don't use this - /* - deobfCompile ("MineTweaker3:MineTweaker3-API:${minetweaker_version}") { - exclude group: 'mezz.jei' - exclude group: 'org.ow2.asm' - } - runtime "MineTweaker3:MineTweaker3-API:${minetweaker_version}" - */ - - deobfProvided ("mcp.mobius.waila:Hwyla:${hwyla_version}") { - exclude group: 'mezz.jei' - } -// runtime "mcp.mobius.waila:Hwyla:${hwyla_version}" - - deobfProvided ("cofh:CoFHCore:${mc_version}-${cofhcore_version}:universal") { - exclude group: 'mezz.jei' - } - /* - runtime ("cofh:CoFHCore:${mc_version}-${cofhcore_version}:universal") { - exclude group: 'mezz.jei' - } - */ - - /* - runtime ("cofh:CoFHWorld:${mc_version}-${cofhworld_version}:universal") { - exclude group: 'mezz.jei' - } - - runtime ("cofh:ThermalFoundation:${mc_version}-${thermal_foundation_version}:universal") { - exclude group: 'cofh' - exclude group: 'mezz.jei' - } - runtime ("cofh:ThermalExpansion:${mc_version}-${thermal_expansion_version}:universal") { - exclude group: 'codechicken' - exclude group: 'cofh' - exclude group: 'mezz.jei' - } - */ - - deobfProvided ("com.blamejared:MTLib:${mtlib_version}") { - exclude group: 'mezz.jei' - } - /* - runtime ("com.blamejared:MTLib:${mtlib_version}") { - exclude group: 'mezz.jei' - } - */ - - deobfProvided ("thaumcraft:Thaumcraft:${mc_version}.2:6.1.BETA26") { - exclude group: 'mezz.jei' - } - deobfProvided ("baubles:Baubles:${mc_version}:1.5.2"){ - exclude group: 'mezz.jei' - } - // TODO: Dense Ores, EnderCore, EnderIO - deobfProvided("com.mcmoddev:MMDLib:${mc_version}-${mmdlib_version}") { - exclude group: 'mezz.jei' - } - //runtime "com.mcmoddev:MMDLib:${mc_version}-${mmdlib_version}" - -} - -processResources { - inputs.property 'version', project.version - inputs.property 'mcversion', project.minecraft.version - - from (sourceSets.main.resources.srcDirs) { - include 'mcmod.info' - expand 'version': short_version, 'mcversion': project.minecraft.version - } - - from (sourceSets.main.resources.srcDirs) { - exclude 'mcmod.info' - } - - rename '(.+_at.cfg)', 'META-INF/$1' -} - -jar { - manifest { - if (project.hasProperty('coreplugin')) { - attributes 'FMLCorePluginContainsFMLMod': 'true' - attributes 'FMLCorePlugin': project.coreplugin - } -// attributes 'FMLAT' : '' - } -} - -task apiJar(type: Jar) { - classifier = 'apiClasses' - from apiClasses -} - -task deobfJar(type: Jar) { - classifier = 'deobf' - from sourceSets.main.output -} - -task signJar(type: SignJar, dependsOn: reobfJar) { - // Skips if the keyStore property is missing. - onlyIf { - project.hasProperty('keyStore') - } - - // findProperty allows us to reference the property without it existing. - // Using project.propName would cause the script to fail validation if - // the property did not exist. - keyStore = project.findProperty('keyStore') - alias = project.findProperty('keyStoreAlias') - storePass = project.findProperty('keyStorePass') - keyPass = project.findProperty('keyStoreKeyPass') - inputFile = jar.archivePath - outputFile = jar.archivePath -} - -build.dependsOn signJar - -task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' - from javadoc.getDestinationDir() -} - -artifacts { - if (project.hasProperty('doAPIJar')) { - archives apiJar - } - if (project.hasProperty('doDeobfJar')) { - archives deobfJar - } - if (project.hasProperty('doSourceJar')) { - archives sourceJar - } - if (project.hasProperty('doJavadocJar')) { - archives javadocJar - } +def originalArtifact = { Configuration configuration, String coordinate -> + String[] bits = coordinate.split(':') + def matches = configuration.resolvedConfiguration.resolvedArtifacts.findAll { + it.moduleVersion.id.group == bits[0] + && it.moduleVersion.id.name == bits[1] + && it.moduleVersion.id.version == bits[2] + } + if (matches.size() != 1) { + throw new GradleException("Expected exactly ${coordinate}, found ${matches*.moduleVersion*.id}") + } + matches.first().file +} + +def runtimeLogFailures = { File runDirectory -> + List fatalMarkers = [ + 'Encountered an unexpected exception', 'LoaderException', 'NoClassDefFoundError', + 'NoSuchMethodError', 'NoSuchFieldError', 'IllegalAccessError', 'LinkageError', + 'Exception stopping the server', 'The following mod(s) have been identified as potential causes' + ] + List failures = [] + fileTree(runDirectory) { + include 'logs/**/*.log' + include '*-console.txt' + }.files.each { log -> + int lineNumber = 0 + log.eachLine('UTF-8') { line -> + lineNumber++ + if (fatalMarkers.any { line.contains(it) }) { + failures.add("${log.name}:${lineNumber}: ${line}") + } + } + } + failures +} + +def packagedStacks = [ + Os3: [ + display: 'OreSpawn 3', + artifactVersion: project.orespawn3_version, + modVersion: '3.3.1', + configuration: configurations.legacyDependencyArtifacts, + coordinate: dependencySpecs.orespawn3.coordinate + ], + Os4: [ + display: 'OreSpawn 4 compatibility', + artifactVersion: project.orespawn4_version, + modVersion: project.orespawn4_version, + configuration: configurations.orespawn4CompatibilityArtifact, + coordinate: curseCoordinate('mmd-orespawn', + project.orespawn4_curse_project_id, project.orespawn4_curse_file_id) + ] +] + +packagedStacks.each { stackName, stack -> + File runDirectory = file("${buildDir}/packaged-forge-${stackName.toLowerCase()}-run") + File marker = new File(runDirectory, 'basemetals-runtime-probe.properties') + def prepareTask = tasks.register("preparePackagedForge${stackName}Runtime") { + group = 'verification' + dependsOn releaseJar + dependsOn packagedRuntimeProbeJar + dependsOn tasks.named('verifyReleaseDependencies') + doLast { + delete runDirectory + File sourceRuntime = validatePackagedForgeRoot() + File forge = new File(sourceRuntime, + "forge-${project.minecraft_version}-${project.forge_version}-universal.jar") + java.util.jar.JarFile forgeJar = new java.util.jar.JarFile(forge) + String declaredClasspath + try { + declaredClasspath = forgeJar.manifest.mainAttributes.getValue('Class-Path') + } finally { + forgeJar.close() + } + if (declaredClasspath == null || declaredClasspath.trim().isEmpty()) { + throw new GradleException("Forge runtime has no Class-Path manifest entry: ${forge}") + } + copy { from forge; into runDirectory } + copy { + from new File(sourceRuntime, "minecraft_server.${project.minecraft_version}.jar") + into runDirectory + } + declaredClasspath.trim().split(/\s+/).findAll { + it != "minecraft_server.${project.minecraft_version}.jar" + }.each { String entry -> + String relative = entry.startsWith('libraries/') + ? entry.substring('libraries/'.length()) : entry + File dependency = new File(sourceRuntime, "libraries/${relative}") + if (!dependency.isFile()) { + throw new GradleException("Forge runtime dependency is missing: ${dependency}") + } + copy { from dependency; into new File(runDirectory, "libraries/${relative}").parentFile } + } + File mods = new File(runDirectory, 'mods') + mods.mkdirs() + copy { from layout.buildDirectory.file("libs/BaseMetals-${project.version}.jar"); into mods } + copy { from layout.buildDirectory.file('runtime-probes/basemetals-runtime-probe.jar'); into mods } + copy { + from originalArtifact(configurations.legacyDependencyArtifacts, + dependencySpecs.mmdlib.coordinate) + into mods + } + copy { from originalArtifact(stack.configuration, stack.coordinate); into mods } + new File(runDirectory, 'server.properties').setText('''\ +level-name=world +level-seed=basemetals-release-modernization +level-type=default +online-mode=false +server-port=0 +allow-nether=false +generate-structures=false +spawn-protection=0 +max-tick-time=-1 +''', 'UTF-8') + new File(runDirectory, 'eula.txt').setText('eula=true\n', 'UTF-8') + } + } + + def previous = prepareTask + ['Fresh', 'Reload'].each { phase -> + def dependencyTask = previous + def processTask = tasks.register("packagedForge${stackName}${phase}Process", Exec) { + group = 'verification' + dependsOn dependencyTask + workingDir runDirectory + ByteArrayOutputStream console = new ByteArrayOutputStream() + doFirst { + console.reset() + marker.delete() + File javaExecutable = java8Launcher.get().executablePath.asFile + File forge = new File(runDirectory, + "forge-${project.minecraft_version}-${project.forge_version}-universal.jar") + commandLine javaExecutable, + '-Dforge.logging.console.level=info', + "-Dbasemetals.probe.phase=${phase.toLowerCase()}", + "-Dbasemetals.probe.expectedOrespawn=${stack.modVersion}", + "-Dbasemetals.probe.marker=${marker.absolutePath}", + '-jar', forge, 'nogui' + standardOutput = console + errorOutput = console + } + doLast { + new File(runDirectory, + "${stackName.toLowerCase()}-${phase.toLowerCase()}-console.txt") + .setText(console.toString('UTF-8'), 'UTF-8') + if (!marker.isFile()) { + throw new GradleException("${stack.display} ${phase} probe marker is missing") + } + Properties result = new Properties() + marker.withInputStream { result.load(it) } + if (result.getProperty('phase') != phase.toLowerCase() + || result.getProperty('registered') != 'true' + || result.getProperty('orespawn') != stack.modVersion) { + throw new GradleException("${stack.display} ${phase} probe result is invalid: ${result}") + } + File generatedOreConfig = stackName == 'Os3' + ? new File(runDirectory, 'config/orespawn3/basemetals.json') + : new File(runDirectory, 'config/basemetals-orespawn.json') + if (!generatedOreConfig.isFile()) { + throw new GradleException("${stack.display} did not materialize Base Metals ore data") + } + def generated = new JsonSlurper().parse(generatedOreConfig) + def generatedRules = stackName == 'Os3' ? generated.spawns : generated.ores + if (!(generatedRules instanceof Map) || generatedRules.size() != 11) { + throw new GradleException("${stack.display} loaded ${generatedRules?.size()} ore rules, expected 11") + } + String latestLog = new File(runDirectory, 'logs/latest.log').getText('UTF-8') + if (latestLog.contains('Fallback Ore Spawn Generator Enabled!') + || (stackName == 'Os3' + && !latestLog.contains('Loading Integration For basemetals')) + || (stackName == 'Os4' + && !latestLog.contains("worldgen provider 'basemetals' revision 1 is active"))) { + throw new GradleException("${stack.display} did not take exclusive ownership of Base Metals ore generation") + } + List failures = runtimeLogFailures(runDirectory) + if (!failures.isEmpty()) { + throw new GradleException("${stack.display} ${phase} logged runtime failures:\n" + + failures.take(20).join('\n')) + } + } + } + previous = processTask + } + tasks.register("packagedForge${stackName}RuntimeTest") { + group = 'verification' + description = "Creates and reloads a packaged Forge world with ${stack.display}." + dependsOn previous + } } +tasks.register('packagedForgeRuntimeTest') { + group = 'verification' + description = 'Runs fresh/reload packaged-server qualification with OreSpawn 3 and OreSpawn 4.' + dependsOn tasks.named('packagedForgeOs3RuntimeTest') + dependsOn tasks.named('packagedForgeOs4RuntimeTest') +} + +def mavenUploadUrl = providers.environmentVariable('MAVEN_UPLOAD_URL') + .orElse('https://invalid.invalid/missing-maven-upload-url') +def mavenUploadUsername = providers.environmentVariable('MAVEN_UPLOAD_USERNAME') +def mavenUploadPassword = providers.environmentVariable('MAVEN_UPLOAD_PASSWORD') + publishing { - publications { - mavenJava(MavenPublication) { - groupId project.group - artifactId project.archivesBaseName - version project.version - from components.java - if (project.hasProperty('doSourceJar')) { - artifact sourceJar { - classifier 'sources' - } - } - if (project.hasProperty('doAPIJar')) { - artifact apiJar { - classifier 'api' - } - } - if (project.hasProperty('doDeobfJar')) { - artifact deobfJar { - classifier 'deobf' - } - } - if (project.hasProperty('doJavadocJar')) { - artifact javadocJar { - classifier 'javadoc' - } - } - } - } - repositories { - maven { - credentials { - username secret.username - password secret.password - } - url secret.url + publications { + mavenJava(MavenPublication) { + groupId = project.group.toString() + artifactId = base.archivesName.get() + version = project.version.toString() + if (preparedReleaseDir.isPresent()) { + File prepared = file(preparedReleaseDir.get()) + artifact(new File(prepared, expectedReleaseFiles.get()[0])) + artifact(new File(prepared, expectedReleaseFiles.get()[1])) { classifier = 'sources' } + artifact(new File(prepared, expectedReleaseFiles.get()[2])) { classifier = 'javadoc' } + } else { + artifact(releaseJar) + artifact(tasks.named('sourcesJar')) + artifact(tasks.named('javadocJar')) + } + pom { + name = 'Base Metals' + description = 'Common metals, alloys, tools, armor, and world generation for Minecraft.' + url = 'https://github.com/MinecraftModDevelopmentMods/BaseMetals' + licenses { + license { + name = 'GNU Lesser General Public License, Version 2.1' + url = 'https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt' + } + } + scm { + connection = 'scm:git:https://github.com/MinecraftModDevelopmentMods/BaseMetals.git' + developerConnection = 'scm:git:ssh://git@github.com/MinecraftModDevelopmentMods/BaseMetals.git' + url = 'https://github.com/MinecraftModDevelopmentMods/BaseMetals' + } + } + } + } + repositories { + maven { + name = 'release' + url = uri(mavenUploadUrl.get()) + credentials { + username = mavenUploadUsername.orNull ?: '' + password = mavenUploadPassword.orNull ?: '' + } + } } - } } -curseforge { - if (project.hasProperty('cf_project_id') && project.hasProperty('cf_release_type') && project.hasProperty('cf_changelog_filename') && - ((project.cf_release_type == 'alpha') || (project.cf_release_type == 'beta') || (project.cf_release_type == 'release'))) { - apiKey = secret.curseforgeAPIKey +tasks.register('validateMavenReleaseCredentials') { + group = 'publishing' + doLast { + if (!providers.environmentVariable('MAVEN_UPLOAD_URL').isPresent() + || !mavenUploadUsername.isPresent() || !mavenUploadPassword.isPresent()) { + throw new GradleException('MAVEN_UPLOAD_URL, MAVEN_UPLOAD_USERNAME, and MAVEN_UPLOAD_PASSWORD are required') + } + if (providers.environmentVariable('MAVEN_UPLOAD_URL').get().startsWith('file:')) { + throw new GradleException('Maven release publication must use a remote repository') + } + } +} + +tasks.withType(PublishToMavenRepository).configureEach { + dependsOn tasks.named('validateMavenReleaseCredentials') + if (preparedReleaseDir.isPresent()) { + dependsOn tasks.named('verifyPreparedReleaseArtifacts') + } else { + dependsOn tasks.named('verifyReleaseArtifacts') + } +} + +idea { + module { + downloadSources = true + downloadJavadoc = true + } +} + +eclipse { project { - id = project.cf_project_id - changelog = file(project.cf_changelog_filename) - releaseType = project.cf_release_type - addGameVersion(project.mc_version) - mainArtifact(jar) { - displayName = "$project.description $display_version" - relations { - requiredLibrary 'mmd-orespawn' - requiredLibrary 'mmdlib' - optionalLibrary 'additional-loot-tables' - optionalLibrary 'crafttweaker' - optionalLibrary 'hwyla' - optionalLibrary 'industrial-craft' - optionalLibrary 'mekanism' - optionalLibrary 'the-one-probe' - optionalLibrary 'thermalexpansion' - optionalLibrary 'tinkers-construct' - optionalLibrary 'veinminer' - } - } - if (project.hasProperty('doAPIJar')) { - addArtifact(apiJar) { - displayName = "$project.description $display_version API" - } - } - if (project.hasProperty('doSourceJar')) { - addArtifact(sourceJar) { - displayName = "$project.description $display_version Sources" - } - } - if (project.hasProperty('doDeobfJar')) { - addArtifact(deobfJar) { - displayName = "$project.description $display_version Development" - } - } - if (project.hasProperty('doJavadocJar')) { - addArtifact(javadocJar) { - displayName = "$project.description $display_version Javadoc" - } - } - } - } -} - -sonarqube { - properties { - property 'sonar.host.url', secret.sonarHost - property 'sonar.organization', secret.sonarOrganization - property 'sonar.login', secret.sonarToken - // property 'sonar.projectName', project.archivesBaseName - // property 'sonar.projectKey', "$project.group:$project.archivesBaseName" - // property 'sonar.branch.name', 'master-1.12' - // property 'sonar.branch.target', '' - property 'sonar.junit.reportPaths', "${project.buildDir}/test-results/junit-platform/*.xml" - property 'sonar.jacoco.reportPaths', "${project.buildDir}/jacoco/junitPlatformTest.exec" - } -} - -String getModFile() { - String path = '' - FileTree tree = fileTree(dir: 'src/main/java') - tree.include '**/*.java' - tree.visit { element -> - if (element.file.isFile()) { - element.file.eachLine { String s -> - s = s.trim() - if (s.startsWith('@Mod(')) { - path = "src/main/java/$element.relativePath" - } - } - } - } - return path -} - -String getVersion(String type, String mod_file) { - String major = '0' - String revision = '0' - String patch = '0' - File file = file(mod_file) - def prefix = ~/^(?:public|protected|private) static final String $type = ".*$/ - file.eachLine { String s -> - s = s.trim() - if (s ==~ prefix || prefix.matcher(s).matches()) { - String[] bits = s.split("=") - String interesting = bits[1].trim() - interesting = interesting.substring(1, interesting.length() - 2) - String[] pts = interesting.trim().split("\\.") - - major = pts[0] ?: '0' - revision = pts[1] ?: '0' - patch = pts[2] ?: '0' - } - } - return "$major.$revision.$patch" + buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder' + natures 'org.eclipse.buildship.core.gradleprojectnature' + } + classpath { + downloadSources = true + downloadJavadoc = true + } + synchronizationTasks 'genEclipseRuns' +} + +def configureEclipseBuildship = tasks.register('configureEclipseBuildship') { + group = 'ide' + description = 'Configures Buildship to use the wrapper and this invocation\'s Gradle cache.' + doLast { + File preferencesFile = file('.settings/org.eclipse.buildship.core.prefs') + Properties preferences = new Properties() + if (preferencesFile.isFile()) { + preferencesFile.withInputStream { preferences.load(it) } + } + Map required = [ + 'eclipse.preferences.version' : '1', + 'connection.gradle.distribution' : 'GRADLE_DISTRIBUTION(WRAPPER)', + 'connection.gradle.user.home' : gradle.gradleUserHomeDir.canonicalPath, + 'connection.project.dir' : '', + 'gradle.user.home' : gradle.gradleUserHomeDir.canonicalPath, + 'override.workspace.settings' : 'true' + ] + required.each { key, value -> preferences.setProperty(key, value) } + preferencesFile.parentFile.mkdirs() + preferencesFile.withOutputStream { + preferences.store(it, 'Generated by configureEclipseBuildship.') + } + } +} + +tasks.named('genEclipseRuns') { + finalizedBy configureEclipseBuildship, 'isolateEclipseProductionRuns' +} + +tasks.named('eclipse') { + dependsOn tasks.named('genEclipseRuns') +} + +tasks.register('isolateEclipseProductionRuns') { + group = 'ide' + description = 'Repairs Forge 1.12 launches for spaces and keeps them production-only.' + doLast { + ['BaseMetals_Client.launch', 'BaseMetals_Server.launch'].each { name -> + File legacy = file(name) + if (legacy.isFile() && legacy.getText('UTF-8').contains('MAIN_TYPE" value="GradleStart')) { + if (!legacy.delete()) { + throw new GradleException("Could not retire obsolete ForgeGradle 2 launch ${name}") + } + } + } + ['runClient.launch', 'runServer.launch'].each { name -> + File launch = file(name) + if (!launch.isFile()) { + throw new GradleException("ForgeGradle did not generate ${name}") + } + String contents = launch.getText('UTF-8') + def programArguments = contents =~ /()/ + if (programArguments.count != 1) { + throw new GradleException("ForgeGradle generated malformed program arguments in ${name}") + } + String arguments = programArguments[0][2] + ['cache', 'metadata', 'to-srg', 'to-obf'].each { flag -> + String prefix = "--${flag} " + int valueStart = arguments.indexOf(prefix) + if (valueStart < 0) { + throw new GradleException("ForgeGradle omitted --${flag} from ${name}") + } + valueStart += prefix.length() + int valueEnd = arguments.indexOf(' --', valueStart) + if (valueEnd < 0) { + throw new GradleException("ForgeGradle generated an unterminated --${flag} path in ${name}") + } + String value = arguments.substring(valueStart, valueEnd) + if (!value.startsWith('"') || !value.endsWith('"')) { + arguments = "${arguments.substring(0, valueStart)}"${value}"${arguments.substring(valueEnd)}" + } + } + contents = contents.replace(programArguments[0][0], + programArguments[0][1] + arguments + programArguments[0][3]) + if (!contents.contains('org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE')) { + contents = contents.replace('', + ' ' + + System.lineSeparator() + '') + } + String eclipseModClasses = file('bin/main').absolutePath + if (contents.contains('key="MOD_CLASSES"')) { + contents = contents.replaceAll(//, + java.util.regex.Matcher.quoteReplacement( + "")) + } + contents = contents.replaceAll(//, + '') + launch.setText(contents, 'UTF-8') + } + } +} + +tasks.register('verifyEclipseProductionClasspath') { + group = 'verification' + description = 'Verifies Java 8, launcher identity, path quoting, merged output, and test isolation.' + dependsOn tasks.named('genEclipseRuns') + doLast { + File prefs = file('.settings/org.eclipse.buildship.core.prefs') + if (!prefs.isFile()) { + throw new GradleException("Missing Eclipse Buildship configuration: ${prefs}") + } + Properties buildship = new Properties() + prefs.withInputStream { buildship.load(it) } + if (buildship.getProperty('connection.gradle.distribution') != 'GRADLE_DISTRIBUTION(WRAPPER)' + || file(buildship.getProperty('connection.gradle.user.home')).canonicalFile + != gradle.gradleUserHomeDir.canonicalFile) { + throw new GradleException('Buildship does not use the wrapper and selected Gradle cache') + } + String projectMetadata = file('.project').getText('UTF-8') + if (!projectMetadata.contains('org.eclipse.buildship.core.gradleprojectnature') + || !projectMetadata.contains('org.eclipse.buildship.core.gradleprojectbuilder')) { + throw new GradleException('Eclipse project metadata is missing Buildship integration') + } + String eclipseClasspath = file('.classpath').getText('UTF-8').replace('\\', '/') + if (!eclipseClasspath.contains("development-dependencies/OreSpawn-${project.orespawn3_version}-development.jar") + || eclipseClasspath.contains('renamer/renamed/mmd-orespawn-')) { + throw new GradleException('Eclipse does not use the signature-free remapped OreSpawn 3 dependency') + } + ['runClient.launch', 'runServer.launch'].each { name -> + File launch = file(name) + String contents = launch.getText('UTF-8').replace('\\', '/') + List forbidden = [ + 'src/test', 'bin/test', 'build/classes/java/test', + 'junit-', 'mockito-', 'byte-buddy', 'objenesis' + ].findAll { contents.contains(it) } + if (!forbidden.isEmpty()) { + throw new GradleException("${name} exposes test code/dependencies: ${forbidden}") + } + if (!contents.contains('MAIN_TYPE" value="net.minecraftforge.launcher.Main"') + || !contents.contains('JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-8') + || !contents.contains('ATTR_EXCLUDE_TEST_CODE') + || !contents.contains('PROJECT_ATTR" value="BaseMetals"') + || contents.contains('${MC_VERSION}') + || !contents.contains('MC_VERSION" value="1.12.2"')) { + throw new GradleException("${name} has the wrong launcher, JRE, project, or Minecraft version") + } + String expectedModClasses = file('bin/main').absolutePath.replace('\\', '/') + if (!contents.contains('MOD_CLASSES" value="' + expectedModClasses)) { + throw new GradleException("${name} does not use Eclipse's merged production output") + } + ['cache', 'metadata', 'to-srg', 'to-obf'].each { flag -> + if (!contents.contains("--${flag} "")) { + throw new GradleException("${name} does not quote its --${flag} path") + } + } + } + } +} + +tasks.register('prepareEclipse') { + group = 'ide' + description = 'Generates Forge launches and Eclipse metadata, then verifies production isolation.' + dependsOn tasks.named('eclipse') + dependsOn tasks.named('verifyEclipseProductionClasspath') +} + +tasks.named('verifyEclipseProductionClasspath') { + mustRunAfter tasks.named('eclipse') +} + +tasks.register('verifyWorkflowContracts') { + group = 'verification' + description = 'Validates pinned CI, tag, and multi-target release-dispatcher contracts.' + inputs.files(fileTree('.github/workflows') { include '*.yml' }) + doLast { + Map> required = [ + 'ci.yml': [ + 'master-1.12', 'feature/**', 'Cold Forge bootstrap', + 'Build, test, and audit', 'stage-legacy-dependencies.sh', + 'packagedForgeRuntimeTest', 'prepareEclipse', + 'Verify reproducible release archives' + ], + 'codeql-analysis.yml': [ + 'master-1.12', 'feature/**', 'github/codeql-action/init@', + 'stage-legacy-dependencies.sh', 'clean classes' + ], + 'validate-gradle-build.yml': [ + 'master-1.12', 'feature/**', 'gradle/actions/wrapper-validation@' + ], + 'release-on-tag.yml': [ + "tags:\n - '*.*.*.*'", 'Build, test, and audit', + 'deploy-release.yml', '**Nothing has been published.**' + ], + 'deploy-release.yml': [ + 'master-1.12)', 'master-1.18)', + 'stage-legacy-dependencies.sh', 'stage-orespawn-release.sh', + "mmdlib) curseforge_dependencies+=('261744(required)')", + 'confirm_live_publication' + ] + ] + required.each { name, fragments -> + File workflow = file(".github/workflows/${name}") + if (!workflow.isFile()) { + throw new GradleException("Missing workflow ${name}") + } + String text = workflow.getText('UTF-8').replace('\r\n', '\n') + List missing = fragments.findAll { !text.contains(it) } + if (!missing.isEmpty()) { + throw new GradleException("${name} is missing contract fragments ${missing}") + } + text.eachLine { line -> + def match = line =~ /^\s*uses:\s*([^\s#]+)(?:\s+#.*)?$/ + if (match.matches() && !(match.group(1) ==~ /[^@]+@[0-9a-f]{40}/)) { + throw new GradleException("${name} has an unpinned action: ${line.trim()}") + } + } + } + } +} + +tasks.named('check') { + dependsOn tasks.named('verifyWorkflowContracts') } diff --git a/gradle.properties b/gradle.properties index 9c204234..ad9340df 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,60 +1,93 @@ -org.gradle.daemon = false +org.gradle.daemon=false +org.gradle.jvmargs=-Xmx4G +org.gradle.configuration-cache=false +org.gradle.caching=true +org.gradle.parallel=false +net.minecraftforge.gradle.merge-source-sets=false -group = com.mcmoddev -archivesBaseName = BaseMetals -name = BaseMetals -description = Base Metals +mod_group=zone.moddev.mc.basemetals +mod_version=2.5.1.112021 -mc_version = 1.12 +# Generic release-dispatcher metadata. +minecraft_version=1.12.2 +loader_name=forge +loader_code=1 +java_version=8 +java_toolchain_version=8.0.502+7 +java_setup_version=8.0.502+7 +gradle_java_version=17 +mavenizer_java_version=25.0.3+9 +curseforge_project_id=240967 -fg_version = 2.3-SNAPSHOT -forge_mc_version = 1.12.2 -forge_version = 14.23.5.2847 -mcp_mappings = stable_39 +forge_version=14.23.5.2859 +forge_installer_sha256=DBBA1CD1BF34A4B82148BAC50A6150F63FFCB2D5DC7D88A0508C27FDCFF15B76 +mappings_channel=stable +mappings_version=39-1.12 -cf_project_id = 240967 -cf_release_type = release -cf_changelog_filename = CHANGELOG.txt +# Exact CurseForge artifacts used by the source tree and release checks. +mmdlib_curse_project_id=261744 +mmdlib_curse_file_id=2712947 +mmdlib_version=1.0.0-rc2.36 +mmdlib_sha256=FE2229E6755A5FD306C33CC22DCCF055378D371339133E4912C5DC9213E360AF -//coreplugin = com.mcmoddev.lib.asm.ASMPlugin +orespawn3_curse_project_id=245586 +orespawn3_curse_file_id=2913786 +orespawn3_version=3.3.1.179 +orespawn3_sha256=86A5E567950D5428F413A0C744FD4EA6DF5807955CBD444392595A1871CC1DFA -doSourceJar = true -// doAPIJar -doDeobfJar = true -doJavadocJar = true +orespawn4_curse_project_id=245586 +orespawn4_curse_file_id=8843769 +orespawn4_version=4.0.17.112021 +orespawn4_sha256=DA99AC45B663E0FB582AC175E7D5AC53C962BD03F00E79299C4BE0E33E9DCCF2 -ccl_version=3.2.2.+ -ccc_version=2.4.1.+ -nei_version=2.4.2.+ -jei_version=4.12.0.+ -mantle_version=1.3.2.+ -tconstruct_version=2.10.1.87+ +alt_curse_project_id=243157 +alt_curse_file_id=2691613 +alt_version=2.0.3.45 +alt_sha256=D5661DBF99859E8C9CF29704AB0FD4A132D062031A4023A0FF5E6F9D06ACE3E2 + +mantle_curse_project_id=74924 +mantle_curse_file_id=2550550 +mantle_version=1.3.2.24 +mantle_sha256=7758817445D55B65581A34A906EE01155C4598FDDF06E7D72944C840A1105184 + +tconstruct_curse_project_id=74072 +tconstruct_curse_file_id=2571785 +tconstruct_version=2.10.1.87 +tconstruct_sha256=B1E21352C7BCEC95E33769308D9E70CC83E8F3A97C27FB94F4F0F55CE3CF96F2 + +conarm_curse_project_id=287683 +conarm_curse_file_id=2622725 conarm_version=1.1.2 -baubles_version=1.5.2+ -thaumcraft_version=6.1.BETA+ -mcmp_version=2.3.3 -mcmp_experimental_version=2.0.1_31 -top_version=1.4.18-10 -alt_version=2.0.3.42+ -orespawn_version=3.2.+ -tesla_version=1.0.63 -bge_version=2.5.0-beta+ -bmi_version=2.5.0-beta+ -bme_version=2.5.0-beta+ -fme_version=2.5.0-beta+ -mme_version=2.5.0-beta+ -cofhcore_version=4.3.6.+ -mekanism_version=9efd716ea0 -ic2_version=2.8.73-ex112 -minetweaker_version=3.+ -mtlib_version=3.+ -ct_version=4.1.9.+ -ct_api_version=4.1.9.+ -hwyla_version=1.8.23-B38_1.12 -veinminer_version=1.12-0.38.2.647+b31535a -endercore_version=+ -enderio_version=+ -cofhworld_version=1.0.+ -thermal_foundation_version=+ -thermal_expansion_version=+ -mmdlib_version=1.0.0-rc+ \ No newline at end of file +conarm_sha256=C1EB6F2BB127652D8FDEAC21FF4BF376F17804E2A5B8EDF14C7C082497AF58A1 + +thaumcraft_curse_project_id=223628 +thaumcraft_curse_file_id=2629023 +thaumcraft_version=6.1.BETA26 +thaumcraft_sha256=9425F8643581B27FF8845B087C8BC6FC10425A32942F1A3F0E265CE6B38F7B5F + +baubles_curse_project_id=227083 +baubles_curse_file_id=2518667 +baubles_version=1.5.2 +baubles_sha256=B32010B2F2778AA1188585E7EAD91AD46D4CB2C715F9C778A61848BA7FE51F8D + +cofhcore_curse_project_id=69162 +cofhcore_curse_file_id=2920433 +cofhcore_version=4.6.6.1 +cofhcore_sha256=E07B0C48DEF9CE8CFAA4CF7A7C656BF7F7D6815F74FBCC2957DD43EFA78486A9 + +legacy_basemetals_curse_project_id=240967 +legacy_basemetals_curse_file_id=2712965 +legacy_basemetals_version=2.5.0-rc2.332 +legacy_basemetals_sha256=034FD791A9E77345C19F6098C01D4B5B66F90EF4A953FB0831089935EAD9DFFB + +# CurseForge publication contract. +cf_project_id=240967 +cf_release_type=release +cf_changelog_filename=CHANGELOG.txt +cf_changelog_type=text +cf_versions=1.12.2 +cf_requirements=mmd-orespawn,mmdlib +cf_optionals=additional-loot-tables,baubles,constructs-armory,cofh-core,thaumcraft,tinkers-construct + +create_source_jar=true +create_javadoc_jar=true diff --git a/gradle/prepare-packaged-forge-runtime.sh b/gradle/prepare-packaged-forge-runtime.sh new file mode 100644 index 00000000..016bea12 --- /dev/null +++ b/gradle/prepare-packaged-forge-runtime.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -ne 2 ]]; then + echo "usage: $0 " >&2 + exit 2 +fi + +runtime="$1" +java8="$2" +version="1.12.2-14.23.5.2859" +installer="${runtime}/forge-${version}-installer.jar" +expected="$(sed -n 's/^forge_installer_sha256=//p' gradle.properties)" + +if [[ -e "$runtime" ]] && [[ -n "$(find "$runtime" -mindepth 1 -maxdepth 1 -print -quit)" ]]; then + echo "Packaged Forge destination must be empty: $runtime" >&2 + exit 1 +fi +mkdir -p "$runtime" + +curl --fail --location --silent --show-error \ + "https://maven.minecraftforge.net/net/minecraftforge/forge/${version}/forge-${version}-installer.jar" \ + --output "$installer" +actual="$(sha256sum "$installer" | awk '{print toupper($1)}')" +if [[ "$actual" != "$expected" ]]; then + echo "Forge installer SHA-256 is $actual; expected $expected" >&2 + exit 1 +fi + +"$java8" -jar "$installer" --installServer "$runtime" +installed="$runtime/forge-${version}.jar" +universal="$runtime/forge-${version}-universal.jar" +test -f "$installed" +cp "$installed" "$universal" +test -f "$runtime/forge-${version}-universal.jar" +test -f "$runtime/minecraft_server.1.12.2.jar" +test -d "$runtime/libraries" diff --git a/gradle/stage-legacy-dependencies.sh b/gradle/stage-legacy-dependencies.sh new file mode 100644 index 00000000..56afd629 --- /dev/null +++ b/gradle/stage-legacy-dependencies.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -ne 1 ]]; then + echo "usage: $0 " >&2 + exit 2 +fi + +destination="$1" +properties="gradle.properties" +if [[ ! -f "$properties" ]]; then + echo "Run this script from the Base Metals project root" >&2 + exit 1 +fi + +value() { + sed -n "s/^$1=//p" "$properties" +} + +stage() { + local slug="$1" + local project_id="$2" + local file_id="$3" + local expected_sha="$4" + local module="${slug}-${project_id}" + local target_dir="$destination/curse/maven/$module/$file_id" + local target="$target_dir/$module-$file_id.jar" + local temporary="$target.download" + + mkdir -p "$target_dir" + if [[ ! -f "$target" ]] || [[ "$(sha256sum "$target" | awk '{print toupper($1)}')" != "$expected_sha" ]]; then + rm -f "$temporary" + curl --fail --location --silent --show-error \ + "https://www.curseforge.com/api/v1/mods/$project_id/files/$file_id/download" \ + --output "$temporary" + actual_sha="$(sha256sum "$temporary" | awk '{print toupper($1)}')" + if [[ "$actual_sha" != "$expected_sha" ]]; then + echo "$slug SHA-256 is $actual_sha; expected $expected_sha" >&2 + rm -f "$temporary" + exit 1 + fi + mv "$temporary" "$target" + fi + printf '%s %s\n' "$expected_sha" "$target" +} + +mkdir -p "$destination" + +stage mmdlib "$(value mmdlib_curse_project_id)" "$(value mmdlib_curse_file_id)" "$(value mmdlib_sha256)" +stage mmd-orespawn "$(value orespawn3_curse_project_id)" "$(value orespawn3_curse_file_id)" "$(value orespawn3_sha256)" +stage mmd-orespawn "$(value orespawn4_curse_project_id)" "$(value orespawn4_curse_file_id)" "$(value orespawn4_sha256)" +stage additional-loot-tables "$(value alt_curse_project_id)" "$(value alt_curse_file_id)" "$(value alt_sha256)" +stage mantle "$(value mantle_curse_project_id)" "$(value mantle_curse_file_id)" "$(value mantle_sha256)" +stage tinkers-construct "$(value tconstruct_curse_project_id)" "$(value tconstruct_curse_file_id)" "$(value tconstruct_sha256)" +stage constructs-armory "$(value conarm_curse_project_id)" "$(value conarm_curse_file_id)" "$(value conarm_sha256)" +stage thaumcraft "$(value thaumcraft_curse_project_id)" "$(value thaumcraft_curse_file_id)" "$(value thaumcraft_sha256)" +stage baubles "$(value baubles_curse_project_id)" "$(value baubles_curse_file_id)" "$(value baubles_sha256)" +stage cofh-core "$(value cofhcore_curse_project_id)" "$(value cofhcore_curse_file_id)" "$(value cofhcore_sha256)" +stage base-metals "$(value legacy_basemetals_curse_project_id)" "$(value legacy_basemetals_curse_file_id)" "$(value legacy_basemetals_sha256)" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 0d4a9516871afd710a9d84d89e31ba77745607bd..b1b8ef56b44f16b14dc800fa8103a6d89abb526f 100644 GIT binary patch literal 48462 zcma&NV{|3jwk;gnwr$(CRk3Z`Sy9Ed?Nn^ruGlsztklcC=e7I2x9>aqJFB(1eyu-q z%|3b`eLzVT6buar3JMAc2#EOW{C^)LAZQ?YaW!FjX$1*JIcZUG1yyl%HEd!6f#E+}*Jo*NafvM<-FbE0;-_L#rp}qdn%JEoAVNlEB#J^Oq`mU_#*ev4HLmc> zjXz_hFft^><#omb;Zer-%wm4hxo!wjuX3hBldg(^-RiOleKin`>KHfL3P*{k?(rji(#j2Cc0K509#>qu=-T&B!-5EBi(+ zIuTD-qfcAYgS@`Fb2^-p)4#o6A3z0&fp?~cV=CRsAeCmO4ZQ5kKgC%0el=Q&Rhd#k zaGmAbUW8uKC}-C0s~2);d{;mpsNBx9rn__66W{AhaSvJEK+c0b6ARO+l(CI7E|S5x zhaYP--@F<|99X&)9`q^2(^-Zu^Tzfm)v|gkTJHQ!G*zIg5hzoygeXZoYUEJ;iFkE# zq^r$*c|>Hmn3GapzcDYnjgSFiO^NFyTR5AH#mh%zRToMpEi(r)1$5)h455DuV}0al z!*psWuL@Ke-2gvftfMEGf9YEi^<{B@qru zINgo+YsE&LN?)1qItJoNhISp-fZ86`XR#*6xcvM~_7=JHUX;K9*=Gu5X~ zix|O2d=&C#u_w{=B$eCpJ4L*6i7={j+{Og~`Emz@&98}6s<-p^)`0fXE4cJBP{>)Ltb>JwcqI>yz z0-r-SEhC@p)XOoh|1|XgjFaREHfsu4dAGVz*k#m+V<4 zHqvlud6=;#QWHUoTR_a8Y8+heN?M%n1@0YLiaN@GuOPNd26tik7eKulTx?mM-R!1H znB6+H{^krFXg_b{y=QeCT~qR3T4}l+b!Oz9;~|3*6F<3?#|DYYW&1RtFE)ILZ!`85 zVmvrZkLTzf31unH7Cc5E0iFShqlBE9hgEnRJH1juII*vyp&xd!g`q}X_6WT6E$hhQ`Vdp9k^<)VS?lj!cTh z7FQcQAVA@jL^cXod8cnhKG2TS9+;QU6Kq>}UOY3&TL9gXbl{Fv8@WsF=z7>X0To@$ zY@Oi1uc|MdJ$>Kn{@!g_e`-I&Tpwfg9cr>(iakDX1qciCG_1y!Di#4_)lE!bWJbrp z5aUonb6m-?tiQyR_`P#~SOu+tb_ev6JO>EbEhHK@KbeT0_FDo>dl9bMg)>xmCNB*g zG5NC8ABavuTEZVGW6jP*nAqRt3W?7Iigc-EE~zpNJXRAE z>`~RO9$892j&I1kV;9U)xT8^}IeV`n{}QDtj2o-RBt`DGZUOO;O*lFCb_vpyGh*;95PfeGu!dyrmZ9VJ3Z*upg z6R-3Lr%_55$Hw1^{+KWx0#z`T7O6sXo1h;m?B_ur`X2bFz-SzDrL zpk^@B<+I6imc@7vip za%1jMB7q@1j# zz{u?YojZMW{5j$@h=v4iu2mTu7IzI|)Sxn!74=*J>1a&?Xjt z2%JhSi#4huEcD9qdR9Lj4vwmfnL{%+vQ{f-KgYeqin(OPd8+(g*Uq#TLxQjD4 zLCL%ul(V&PAPlAx8D`@K8Rc`{GPecQ<)d=KWel0ejFeeXGQ6o7601B!!I@RY&eDriADD6wP6DcFKDLZ|lO#YwnrNCZ)zRJpdxX_nPZa4j#$j6v!h|6p!dH}MY6#B`@%6=) z-HigguDACKBULnon^FKzazF|Y1{t(U5rUGnEU|}djVsWT-F>@@mNx?_$kF51QF4C5 zStKR$^3(fw85(4HGs9{mUTtn1)3PwxTN?6}j;32&vJ^BiPHfndLkdU5sOemXKGyCZ z@<7j(k>DNeo~QXyJkFWk!7(y1SB%nA3{v~P2c8ooKa4auM!el!Q_=;lJ$c5ADqE+^ zX8*|A99v;jWPrm(8=h;2ZAj|(vVbx~wQ{N%v;eYLD_BB2LAEWCs@xauyBDl(_HIBvA(XJ7B1E;O zJYCJ8xFJh7f5sr;Y#Wp_`$4Z_H4e9bGiBp?Qu&2!@%Bl2dT5evfFO*^hLDiBu2%Jl z*WAlL5PaQ7skJa(qVysky}DQquZ8U?2@UyJ8zB#=U_E>MgE%XA$CtfL31m$rATJvC zs@!crc0=128PM=Zp zW_5Czv9))n_8Ru?{pxM2F8^r%*O41}RnONbSj*piG%`nyF>6ky=|;B&k8iot(J=kyoU3p<_zaAX(1ijzf*uXA zZ_5jeC{Lks+&QeFIlmzZi3+fsF4fNW^~kvC4Q*T-vrNP!x9xnen12lZQM=1_MdW76LKX(GuW`%T~dM^YX6+ras|Xy4Qhfcq=D+z-P-ea z`T;^gj3+grr3^hwqcNTJErl$z+k>{bYFm6QV%7Opth?9+>|Dn)O@`7F@=j-XSqGPW zjUAu%b3Er@;j1%RZxVDhI3sakg-gvTLOSV7;FV6ED=(5;UG??=WADZw^=$4AyFh#}VMe3afM^pF zFa}-nM8X=K?Jy02*o02@6k{ z%O!hBhjXlXKdhy3A{xGB<##e|j3^dFv~~%v2_H{t(mN7NVeS~51?D&Ozbxa`qwZ_4 z;C#Q#fL1sua%ggucgIEHZtcY=Ag&GgE|h7Q{77D!WUq`;SSGEE0pU;aoj<7-JCAvf zduN=(tx3Mb+EUXKoax|v;8b@#HJ&Q|!g4ryrl|R>WlAv?IH`bk)I24;eE4NIq@SLK31LD4+w~#3iN{=<`<1R!t^$@K5>U6%W=%8_ANuR5 zs(IDuI18ftirTDARnGmF%;iz+4{MlMihJw_l!0Y)NttXC_t+s)V<EY>=Xin*nGX79k6vQ?beRk zy_J>@YSC_gMIG$yjO-y&o>S6xtfT27aSs>e|`x(f2R1bM}*518~%x>1Yct=18b&Z>GiS*>VB$+i2876zL)1cT zN33g=g|>xWE2)dds5m2+8Vy)m-u@NHOlGYxxjam21r1;xWtT0TgqKZrl}*LSkqFt4 zNTI1=3o%C*!-i;iWnlca$stRdwITA1?#fD~5OIqIQAM18BwO_u>hqL&OAANiF|8rG z_IZ9mp?FA-{Gq9+Ky<#NgL1gWJixfO0ziP$4T4G>vsvqC-NQh+A64F4! z-(t<=AbPSG%`mTl6BJtH~3RmvPhQlE-EUkEoBIP(_WMN zK~Fe!siee{M*ns1hkp5(2}vX#%u+T!Abh=<_gEx_QW?h4V@B>uOCEetEe01tl)^`V z(=cOLmuOB;8&&m%_6pcyrt83UXkJ`f9I&0KxY09}RTTs!l^_7~8$tPA%Hm#&$k0;# zF;O0zCGo0IN)X~SyKDoY1DW{Ulce|V9w=ld;U`z$t$>8U!Gu8V?_LAJAudt3eI#*! z2i9~F=kP5m>!bmb%1e~b1!1gz01Py(Yw5gOsFN#o1a&d|=PpgN(#UVreY9^99I0iG zaYE@>(C^V7pnoB~#w$2C1_TIb1N5Je&iao?S2A*TF>@vpHg`31{uk<9{zf_}s&z%dL-Fo)C$yl$%pAdqU!HJgp zh_{m1imk{&{ScyeuziqZHu5cto0{S}^BlXu% z0~;>_yHGd#?Kt8ErxK)z6ojj5SacQobw)-8`c!$HOI*V6eyqou{1Upm%_p!BY^t(D zDtn(oQ!jff`ddGSD;P8Hes!v)OKW-*>mS&#i0ow87;h>(=Cu0>b4)|=EegbN5=Xkh z9Ge13=3z#sk+fT<)PuUUf_%Nx@l!P?t*mni^94p^Ax6b2SVL5U>9dHH!H4DL4}@?@ z?Gpq$C**OmWliYA{5s<|EZ@QI2{-K#brFxfA~AIqq&-WSALHWQ8}%mvaNFasrtnE{ zg=sB4-RF!?)nf{>Wo~kNFgYefoFHBcSr*;iF9B!R=5Np|jv>Uf+mcarG-XGy*kP{z zISVyoPcl_9cOg-@613Qx16OGF#sH&2NTHDa_}vyidmxS~pMfY#AeQvu?AXpWNzi7A z*6&7a7!C9HRU+N{>WYTh0GXoBnXw{lQby^XShgDOw@e8TP}9Y*oFV4MVF#@Ds2A+A zXBEt3a@-IIl)TOcXx;0P;|ihR%Tq@DXeG5p-O{!T7Sg$s1 z8OA4iOx-!>6eK^x{jU-0SvByimK|nZik5zKIvvWVGE)4=x^&5Nx%Qgje!k3VoizaB zip#?$u(R8u{wUFC>tVR8oA%7fs?xEu(gYn>y6BB%vwPR9&RoZE%%RK! zl#Qnkl^+Y*Y4L{Xk(YX&aGj|zSpqO_;C3CTepA!L#4EXO|(eA`Fi+2EQ3!C zo^SpVP?{chQ3uaxu7y>w213e22cdA#l-M2kStPE%sq6vE4M*?3At!S7tIp(tQg(Ml zECjeJw8)*#LYYk_+Txv3rxsH9jJZBRrHp29yJ(^;_PEdn%#U1q`r89}38;XeF{ee& zsZEsUbJ{LtwOjU{vjL(Wvs2!Bx;#^Mzld&TjS@oo3kk=0P36MC-Ie6eHNN&{8b^s z0@jcbdejrrj!>r#Wu=3H1dgjeOI}NkhmE}K+UK&M>%7b!n&{0Zixk%^)6#@=V~IZN zxG>9kl&STQth}qScidfg58d2dF|v_U<@+V^eE@$4x;7oS3)MvWusA?9+%rN>aY#eA_6 zic@S(@e9$9tQM-&-7>X8~#n{5G}nuOu=dSyN+b~jA;_SExZ1H9Q1A}}Rz;XtXUIOP0~ zZzS|~T+%de-nGI$s?wxaJoe+99vmo%xm8o8SNEsAqAE)4LNvHc-1AX24C4k4u3vZmov^_VcxgGxapV(8)_K(^8= z2d{xCrmk(x&514Ly?e{Mf6}h3=oeP7+ZE{%B^c-kK8g0W{tYw3q%zty_Rd@1nbnyHMwabNp-sSyzpV4v>QsnKcQjF67%g~n&3t^1MesVxCzfJ5b=SOI#YfPP^^JGQw=9L1RCMFbrU{8O0LWOUdBK#j&{`tzXX zpe2_{+-8$a+o#%8MUlL4$yK`*--z&3{@Y?jP!m{g5nM+Ht=bD3o}Ok~sBQ_!^!->! z?NDVtyLXzmGYCEmjSCDK*q?Aq1;8fz9l9|z@~l{)R6GfKELc^(nV+TjjI^n0M+S0i z@YOu*Tk>|M6a0_n$(E;#^1Zgif<-CpYiMvyT+Y*9Z?&~IKSwsLa5Q#p_?FqK3lKIw zlp6Hk%lio6)yq>m-`QT2Nj-q!aX7~Hlm^Xh6FNbw z$#ri(Kk*GUHXORu@`aYQU@ zB~S-oIO^~abRPocemkm!W73dbb!j^_xgo_@#W#6p12>w^{){VfeX?U71Xyn9&E zHa1#*!4c;?r}jv7dMN`g#&R_S215)dccDOJr=uz%LIz@zia+LIFjRakROr?P zQ|Xw0Pa8o7&W=fw17`+SqepsQ-Os5v3ncD5|N?N(AHH&`>hLY+CLOluJ z_ErpaT49zK(UcdNmQ%iA-`jS`A_1c|$W86{d_T_T2V-HH3xUqpX0QJSH%i>1i>#vK z&y{;5)^pMB=u;&_DEWakQU>j&+opIrBf~2GUh{`kG{|Z&2Z}5dwG}>Y{W_uQHaR$_ zYH%}$c`CGC-FGCetRdQ@RZ2-%ucC_|R?mHzYEnqC%u9zRBH8wx7po`=EVPMpq+hL2 zTdjVhQn$)++17^cn;<3=bxJy0Z$U;i3AqJMPJO&SuieU&0eVX?eLEEI7Av@#PV_ZQ zsa>I>B5HE996O$z6HyJfhEt^aC><@AnzeN`xs@lv>^pPFtcodrcGyqPSB?#C`Piu0 zh5=hAW|OtT9hs*G?7}@*mG_f7ae@-Nz4{qvne66kco^uD$(JbCo2ttqUm-SMy@kx% z!eDt?5>w5)M!E#C!b#Iu9GqyhUs|QoYWHtR{4espRS-LUt=viY2iygF=-j3kcU#uF z{ka2=zsOuLR}s;&PbbrB`zty&NfZpV*Y;~i*W$EH0JOGS&FMS%VK@)f*%OOrcU3P9 zq4zjhMpx}oc`PWtP!o5Bdlp=(A***TZwVwuZbuB1Pibv5uiHvW{PsE-k5IfCgUz~l z0nMeZU0R>(ajoQ0G%Il)z0BgRR*bsdz5NcqJ<)niF6|PUO0i}<4)q>6wx4K(5>Y_I z4$WMkbCOQFs(krBnl zx85i0*7%Zm(&nKNP?AQ}d~6@?D9dO%@}ouN2paSR;zyUqJuw)1SRy=g%o;g(BD|Bh ztnKV(4fcBgDJ~M@%}n-6ow3xOhnC>C^d?PbS(9=TnO)k5p+W;pu2F4eiG7ts zJVL4M(NiZPQDy*9`H>-P0GWY#=UTnh8feiNF}hCs`8^ZDKy;XIL^9K4Ps&y^#DQSE z-?J z@YOQ9NQi>ZP>^ix5K`R07kWj?`R(B?E*OyR1$Vd;8p%2Y2zEYt4CJM~gVX%MO(E1B zzXhsHn~R1ifq9~dtzuH!*3&W;r`D(Sjrc)m#EI%`Car;CMWcU0c+0r?O!)HpjEvyP zb^;pO-Bn6e-+>dS^o{q&8yEH9v}vuXX`W;NPRlwJdX|59`z?~z{pFE!^u{3k{KkJ55^ zD;F0ldy9W*`d5YP|0(E6|K%}9|D^SIq>wO)4^cJ+yCa&xl*3}hpvcQ1eP_k;@>tz= zOZnw)#fxHc81jPcTM#)jgy|0?n0(jd3IPu-lJ&Tm`#F1)o$GTwYp@dlqy-qiHFCHS zKgikMUx|%x=_%B)>n_y^+HvD2=nP`}-G_0A7)I$yc4`tXS-On8qOkNp>Q^$|Ew%Jm zYx34*(*Z3SF}xw$CA?nG9O3ZH7l)@Dp4EyH>8eXDb}AFz)k*T53iA~gRu&e15u@|% z9Rw?69nQOeJhv^^unjd-VGFwbDzf9K{i(U{xxHyM@-aI+0qP{TU0G~w+Fs>taL#Ik z4+92(Z7n%+okd478;__0GkE`&(C`k8h@?UNnM=F%A~2|TKo)q9F<5`s)KwxJRw~k; z4giS~|8AIVG;rde6I^W6m9fliR^7YT*>&x7wv^?xu(5p45n{|2F>x%?9Jq+~Tqo9# zChbeGm@9!(s;uIKae_4h@`~yIj`Tqct+-M>d>~2PCiQ?UmFUioyy&~h_DTBQ--W|q zqA^UaJMTz4tEggQ*_cQ_LA7j7bLyz8#cpGggy;YBVk!%oSdufoh5-FYAQ)v=d$Bi`G$^~ zm!O;En#M9uCykPzLZ5SHa%?hDHP5P;T4HN0L6J*r9DAvC1WWPOrd{*obfr3yJ?Kl3 z^_6dnXRoi4<$Tr!=4mhHg6ig~BatHR zv%ZMJr-`8w_JyFEzUSQdp0HT>|9QQG?IXj$7Rbx4E)%HauDyY!tedHP ztIbq;D)ckd-eirAHOG7icBH23*ApHA@nG*Jdh}~G?L5C^Xw^+nLWG+>hRi&(fnpY5 z?^hj4si6I{m1u^%i_yk$tco}28X8|}g5*tAEZYF37$f(+xT%XvO^`i^Ig}%cydrwF zlpL!xdO->&@q|8MiJrAxt;z2CP*a+EvV`_2& z<1=p{zjhmmYVkpx#RV=#zuy&7^2Trn=H$nT{OBVF*0z|QH!NxBF%gbqT!BEx zKB!SsSUwSo1Zr?kMM%N)@hG=&m`vRQ6QK6=oIvnUI+|C)dGKM@jNwqG2Xi8;YCUHYRh? zbl@DN-za)+0F9kw>Yv=ioL)01uFp7@AVEB0AH-nmB%j$RC_totFy4BKd;OPCMUMBb zu3oUUK`|{AvkM+@KPZD4Tn$(VlQi&aWV*Uf@DO|FQjLOoVw&C@z~Um*h%Ka-C=n4H z@(Lf&MDJXNS{3Hs@J)11(zo9tGp>wS^b9{Q1WN=Ktn>ZieRZS?k`gb7P4n?cl^7^* zG5-oARAG#i<*z`J0ski%;QCLD-T$AbOHq<{KxIb4=QJRn@MGj=ns0WhZX+uX z=oTjz`o-VviMt1mB0W1vA*7oq1ENz{<*-EU)U;r*ODfV!G-?hdnzhM@rRZ=|qaFTN zX*t~$gc-)M7GS{#34R-n`B)eAPfebN46~61R?j^(Pg3TXR1PyQrO7Mf@xf<3VL0`4 zh(i?-SktJu8Oj?KIy4p@%5ZH;P&p5LB8 z^}7P)9h}vUP+1Hd3nNzNcbR`%1>dSZbWhiXe-CcB+s9e)_w<{bypZ(@cQT`P@ch=d zSOPhExgI31MVFPsClEXe>$~qYQ+d}7(!BE*9y%AjQ47BMDt=#>`1ie)|ES{pFFdHa zI)CK`f3x>)DtZnm!f5=e@g;3iK^jf!RU6hpjYu^V#q0uWLuJ-6={Ua3gDi9#*P7;- z`rm*5)n{2QE{UZ01PVy@_9(amogzzOwYcVgp2>LsJ(}hKbX_!ayZ7=U{!p{BHussVj(W z2z3$zu7h$KK<%}P0YBJ+)0unV*xD&6GusXqs=M=Cl&fP@Ttzfq?>H9TW#qDId+C7? zhD;;HOxDJR4dc_xI7-b6N6nZ@bUWueDk<_9Rju2I*o(i)M0&~%C^ zc)a<25M<^NrsjAccydV2HJu_-1W>b;xrB~Mi@c7FrW-94$-GnKXvF7( zA68!d!gkIo8(URS{(u{zRtrF}B$9@*)KH9POqOW-B$za4Sg-A&PM*on$>$o#L7pH~ z&YW8oJX3T!!@2r4Rr6ac0ZDbtB1b5yc$5}7oZSDvGF0FWTpZ#r7@GfM^MmC-p{9Qj z_JmmlTxO(^(NHqBc$ECU$jQp^;)%xnyr$qvNTd`R@j$8JppDCGQAHQ7?fja9McCUZ^;``VW$1+G#=<;K{_OfH- z_$fp~S3K`;jPNNZnkB@=DFQy3{6+Bq9nOf3~dr4q8zD_t{P4-^%<4kj!U z0aj`=#@G*w?!4fpM? z8Pwb15(Ka*TtDN-2aWK>*hh{R_C}*e*vSTkHdM(ETM!JrJ=1h?(_WL}2p#QXjrKZ_ z0k_yu^;~)#*r>sQP7d_4VBRvWJCzw#TxA{*hktwQI3ST{8{>3$KHJIgMGK6I!d}Q zinmfq&RLRxX8P)_@@vVr0gPu7*)uU<%xS{|Eg;*w1}2=C&?7B zSX?OLt-gZO+<4@tLeF+K0~*|xwMD__KxWgGfsUpj)KyeCM3J-f*uxe|xk;Dlqq%1< zL(PaY@U(>Z#k!C!B45JlmE^~wHSH;r1c^kWTG9_VT~1LN6$a6Yg@kNF?&b0hs+5Dw=0j zR(wcEYmdfgojx+Hzu89*C}4$I7^?^vYKhF(`>=MC)VeeFR}}?j#XeLnp8OhW9%9ND zt6utD8DHnQj5@YJv+$USdN{8apQir2)Z{8_s!BABmG2O#pz5lSh|gf#CI8X4I|U4g zhQwk=VEV+j+-KNxuIk96Bi%^(Sf9}A7o$zHJ5mV~)qP))QQY&^>9}z9z9)PWpw>8T z7#NWNEtnUoUl{DP5(lmy<3;tpLJ3hG|;CGB`3**uH0tf9>;7w;Aq9SRVg1FDpI5y~rY#B|eCNpAXD z9692@_%$t2^nu&4lU~(~_iVf|Cs|mXs-xKlY$-~FZB$!oDK#)JgHZCG)ySDURM=@(i zCpd{Er89|l&)(&5>L6LuWY3yC6)`jPz(Po8pY=AYIBnx3y2Qx6*sT42mpR$zwx!!< zHHCc~tbF^-bje?bo#~Q59Dmw_-VcliCn^FfI*EV)U1NkNA`6Cm=^%j`%M?1Zxa=1U zn#DPNc32&XHHfUfmPx*J+3_GA&g-_pd#wO=Q^5bdhzmm)>s@yO0q|>ROV(hkhJWf@ zqWjI#+9Wx%C+!kp&kxX|XPS5m9CBC&3r>}SwdFd#YF_W78A*CN6mFC)qzOjM);Z&v z#MjdXXMw63v*tbvY+$tDmuHNFunOlRM#qe|eV&|$98!xy{n)-=N?lrkr0_}U^sz|x zs0y);(2Dooa;(9zHzRi=I{GSVcv!6jl%ck@)>JODfR? z%aI)0HvbhzY9K7eYsntq#JvWzj$WCuoyGoPY7;LSPfZlFiWU)X?(-p}s4FXQcpIp00;%Jv;k0t@2vBu4i;rh-?{z}cHTLL9Rz zT8r(1Ws*H~EyH+adP$cGv|7HkeS9p6eOEI*`idH3twkEJ*72|ey4JgISglGV0Vo@qe#)f-=|g%l$S&Onwl@mmdn|sjXXYaQ4MlfzjiK1* zY&hWQyc9?G2}2s1fYnQ}LXpq{!&Kr97d?=a?_xXAU0SXrZE?T+=9os2*v9%Csph*M zW{}m4+PIRmHEI;<=c5$PMrfg#MTs);4Tb_0**o}*cimSWRcxo(;G&&NV+-?W7v*%4ACG#t5J zQP=$g-(mN*;B6s)d9JNkF0#Zz_WA>J;{=2a!IJsiqCV!YLjJ(wUJ`3b$>qcZ!HjDT z2xm;fMSbtJ|3o~tc!jJ+U8a)vX@NcxU8y#u!Puq%R~{sps0msRFO2!GM4}786S7* zxgNmf{q@|Sdnf6_he>gEGX7Hn)uih5nL&&t4`O{?V;;bdl1U~9RAnjNmt~1UPC3mh zrR8ZtHzz1(yOYSK$OjKf;InJ+7mH$WfqI^OG3dhA+S!YmIgRv>2H78?<6A=~%E{ug^P+^b*+f=j32&Nv&Ypq?DcH&Busg^AUDE|p; z8(tQxZs1+0gUX<5~Ah zT0cGckI5%nM~d`uaMJ$o%2bt^##I0UdaQ2>-bpsP4P1Vk8r7EOSr+a!D*Z4shiKFL z35Lvs^i;#;G{%ksUUo8(Nj2DY?u5->J8kqS_#{B`HqS(UkzR|K5&6XI_#FH4?$ znMXeTb$nmr1`|{n*#5H1T%vtU4-H)vrtAchme!ZG#@c+Hrf4uxx$;VU(Dr~N-ich4 zMKpdwot^bPY#kBILFgi?i3W_kV%vn2J+%R5x}TL8I?B~o#VXlmr?i=y`yJi-><;X* zPCDrsU51x;mkr+t18lPs=6)r^gEh2$saaA!qv_< zKQP13J}ptHaUjT_(*x+P}wfV-}57aU3rp#3AB&~e3%y}0ju#22u5@mUIT!GA{* zd%-e2DTmr#$(P6^$&N0oCgR)F9IPR~!Q!x6YI*7dx6LR6n8tj(#1~!0rofeMtT#g* zW%-p@V09>&o>iz0j66K^soJWg(o9#T(8Xx-P3?;J|t~nIDSGPq(?-B zOoNnc5HZhsW(m6!J+yj~kjmjV6GKvhO>%^v5`O2I@4B$Z!~DgelYWdC4P>YfmI$TR zq`atDEhIt5ua)PS;Yz1`FX@3Na6j^uBx_rNKTmgboWGwE6O5;iQiN6Q8>ZX%ApVJS zTEf6oj=@?7klS(JaijG|(gO@dTgxB3#H)4&?+@VWkTc)dl;qK|uv;WRI*cG2`6PiF z4+svy+Bfn&Fs57Jz6i!C(w$w@VWPAbRGak~oN>3vUg|Mmk0NpfURt0*DSJ_e*Gi8I zqshW4F}L&aS8x~4*#{4vOc`gKW99cx*L^69fgPj#?++q9LidItd}<@&#E{ZGz7g|c zFX$uKJ;Qv^NpN*e&EL;l@1br8j8oxO3e`g<911L_jr~Xb0)t$x$A~dFay9(}gt4&L zyb=1<`|)_7(!^xJ14xLBGKXO3`R^_;F01 zG70TiF<5(=pRsJYj!^XjLl_vFJOQPhN#Pkr#G0-m#xG>q)GAHjE4WFhe7Zi83;gte zdDv6+)qrgh3F0}$gPmtb9-Ff1m|xDD$6jX)Dcd5Ms-(@nKM_3)2+hfh6@Cs@-=%Z_ zIinf|ck6rN{EOadGmJ-rzvxZnAL)(mf108HL2v&m)%=a*?3CnX2ZfOQY?ha_11m@UzRqlkhrVbQ@0M(tSSTerx}IH@Dn2={w$iGqU#`v}PuV7I&A9JYNP%sqMn z1bTq*Ok{V>SlVH8H*4X-lO?VzaDQzAaLvc1tTL+To)YOuj^V8mQ?)K-FT(s_!ds-O zeb$rKRR-~g^+_aiGtH6kbJ)!K^ie;ipJ8e;>iy2}73i(1RY-~!(tk2zPj;pwB4k1a zVa~7lF^EE`UH=#eb**88zBH%!WkO0S?_Zu0KpRtXN+XMsAwfT56IZI}&cs+R5N~p3 zlQH7o$(zsQQBPIRmD)i>TfdcgCSKbVVD;VCmO3l1VNbV&rWc9o>Pk>ex!)Nap%NtP z&kKIFMm@k9-HeXj2$((SmG+a-dXvl7q(7n=8)cELHf!@Le+X)=++(}pKC*dcns?>G zVa*fV{2FDIJNaK_jq)WE9MvxiTm6sI%YUn|S=oP0Z`vE#GMZa`4V5byxmv0@8@Zb~ zyBOJuTAG>Im^uIL@!ZrWJy6xL{%n;pEwY87Y^xYSfmmgRcgcEDfz4TJ#{;n|g>8(> zv$(RLnp4oD1Mj>H@ar|0RCy}E{GwvuKOf1FS}O&z-Q)MmCVEK{p~b2xFj@lTn}#s4xg7h+r;n$TZDlT2AXAv z7R^$J?R|*xL^>7HI}e>7{HszA#Y_e8=~8*3zy_J$ejuhByeI0I!w-&%MW7Q-FGMKU z8qPm&IdU3w#^#`d%Vcn&q^w;EEr|w2F@ax^`R;a@p>l`U-T%~f&^`#zG}qdSV)A<0 z^*U=#=#o&gd{o+*s#j$xf+2y^t1Wj9_h}(DNi^aK#jI}z)v1rk-H)gocbgc`wB*?$ zfg~22r!^VEN+n>U8|3{Ebe#!9k|dF8lV*9c&9H~&g|$Ymc-2O^j9w$Q^I)ldd}5zv zQkBFDS2TxDn`p}-{-`br?tUCgyfr0Wbf3QeATbp=9sN|e90U^eVOu0~VT$1A5))@C zPcwzUn7bP^Gd~hLA@8EwiklMmlc^(;uPE%tLecC-iZ$_~jNJnZYn1A%r}=VE(-LG; znh6Q+b;zKz_N7)0SH7t~u#)e>Pr194w7xp;V&CpmJw5j6zBO%yB zjVf*iveYaWlrE~+p8YYym=-QmTd_F!`)ATishn6(oD}hTE2AqnVPF_os`ca^ET@@Z zoo~4YJASOBn<;8#(#3G>n1E)&@JA^3LV7mK^kaJ$((~ASWup3G(%#8O%xFX8XSiN~ zUF0&gDyT`FzIjtA`<-+9RXEKbwu%RtcrG!#-aoN0aj)i z(G|=#b_!z{o1}cIyw#n=j~Ac|NnR@<-CW$c%JFBFTi5JW0BX#4k2o2w{L0EglSN7E zFUcmFVF&U6NBA7!t`Lut>faDk>pW>Lz9BSzsqWvnI<+L#wg=zw+aeL6=70S773#Rq zG@fVM9=1ZibB`>L>hKz>rHG}`pX;dZD>I!_x~u>jsx3;0d$`Q%t7d<8^lkl8w0WZ3 z(HGiok6h^#G2EzIH}G*;!U8FW>@|C+wE+z{@e{wwWEkzUEiT0aDJo2JwZR{zcX$Bz ze2pzE&vKCc6@vE*GIv1LZ=qSg~HR)Jf|ljt#^m2hZF4z|32*7{hd|u`C7{C zjG>}`{SC3Dnc~5%D4yBa!V@}xSBtQ$ZWY^qs3)9jTuIXYMgPF5E0*&A0B(=JEntcVgC%ZO4UKHyuzuSblKNHWJ}OzVpeS z?8|{P8FtkJ=~%YMf1h*@o-YsZkLVQU!43cY~nWEmBt#&Ar%7WClZK8 zSe-!M)B8((tj^wSIm3?e5oe&mQs6BAE#Y7K*^boU^Z#aITL%-H zul5Gx*FKM}n~RnE*Ko3}nXrk8nTw0Ok-d?{|KMda<$n9cFHzkfb4wa&Dp0x>XjayP zg-KZ^Ayey*gb`NecHls@$a-2|Z!Xe^@P`uYYo`Q*jKzDQGPFf^GDQ5rd(-X3n)&f|bD>?`-DktKL<0hWK!cPS>L^@|VH6## zG*0#NtGfzpZpt+e{yL@K$|Lg*JfO%I+hp&kR;NxOJ+y2H49xZA7=^RKObPZi6 zL&R70!l_{PTFcxI#h+WsO^Y<`hE*z1vg9n7nG-6n0xBU8F8yDd}=?${Kl$qim3(S98@^W*vvSs{l zU}!oUIXap-i#nT`er(?avm4Q4-snuM&-cwu#-M{K8n;l1gP$ z3sw?`ls1z%eb%&mNBvLuEci8}-Q`|kUw6;F0-pHb?+A)+BLSn7_@my}6u%J=Ub~(* zU1n~wcfO|73IBZF;|Bhy$0FeO^>lmmZz?ZuZC8$p6<>B{Lsp-*mS05IVU00ergKWv z(LIsLS=?(>QLLQQ?bdTpyO?iiEL`;>(XJw^lA*7FCd|$g@c3VRy#tUf-Lfs*_HNs@ zZQC|>+qT`k+qP}nwz1o`ZNC1_y*J{2=fCentcZ%LwW?M`<;L&dcdwa@4GT@LCkltq=Xfy+OasOLT!lXrqy` zEW9YuDcfQtJ$oJ|Ln|b|q*_a|YPgCbBBfQ|5;-1(P3R`sK~3T`TtVV6yrtDbioJKI zPDV1BAaj#O~V^ll>$# zNC?nv_r5RiH^A2t<)qzcvns9Qd$_UU$`jN;KUSNqMCQiCFCi3A$*D#(v=FXCqz$SB zyC8vjHyJhMy$5kCi}FBy0NdSCJa6{q(|*9I^zwX1NHX*dHOIDB8bsI3_{(*-kkQV@ng|lWd*nWx!(xQ1stGMcRDjH=YUQvY2^uCZuO%-0Jw5az*F1nW_|h zR~z5DT4j&Z7527|#z9b}pmRW}p^|OrU(TWox^&Kn>YUn%%JlZJ^16vzy|O|GnZsf3 zSXEMjOhuYZlh*ikE0&zHt5va@6&GI{1&D+NPop@Tss&f!V4;}nqX@iOvdonoDa}J_ zE-u%qrrUpYVYSGU5NeXJr?#B#3dkObD8uk*U|u*zS;T2YgAk;_kdF0s4A6A*YGO4)#dKwYLQi+*i=C3N85d93 zAe#Lng7EX?@}-FPvIdp0y!`J@^1tg|IHwZ=C-i6LW7u!d>#==7<(?=6?caFCo;)AM zwwV6XHIU7}%D3 z75#&7SiVq=f6k4N*gy{?o~K9`+fsId8Co*62ksPHLm=SB>G)@44I(Fbs1stfE==|e z5WM)k7Hs~OwT#*$%<~0|BEb_6HV0F0=kYy;P zdAZbN(@{*9FL}4bSi-&#J^2;N`G{J?KFD@i^8BEXQq3$Q#~shvw_cx5r%ZlgHz2&Y z*cU<9UD1(G6qg=Yx{LRix``xh^Yi7@j|r7hm00t{(0ei78ZQbt`JV={$XlXvX91YH zxbI<;-YQG@9xrY>Ar~yWklR>hQ-X6TUxD-S!;~b9lu;Tu@f59S=euifnkTO2C*G;S z@TJZ5{$VG<^ThBbq_74=9q9r7DxC6VBngr@olJ}~W87-NEagn(;M*)7Oj2!(TG+}U zsLu!TV4B7DH{}gtanAHawLkpH5_$jk$0~;0`rM1Hjkl;4D-KsjXTl<*z|E`_8Nlb6 zroi&vNu(socja8wZ}9J>;D}esqgs4BR?_u7ZyELz2k%GQjtG%Vx+yeS&QI*AK1Q~e z;1-8)WjT?WqB>et(n%42u5UPI+!F^B7Hx#oW{i;??}{9#vpvk}lwvHPB$=-+pnIAL zGBd3sTO%TRGFw?`Nh>DzU#VeO7C?`w!-QT4ZgBE!WsS1clJ&i=m$ zHn^;?BNx^_wESMCsSKfxi542WFvUJUh%GpT-JP-b+D|wh`H$h4?*AT6uKyK)=>%&^oOXr5Al10+ld z9x<66pEk?hlV|$s!otJ~_Kz3DcB~XFzWq<@HMwvNFc2}VQuS$6g{U$+nN4G0`E zua0)-H1D8k;mm6E{(!pNomCz*qxv$pI3NvG>(+Q4AcJvK#K8 zb9SOKS@GC!pN|JW#<}*37GFj>D1wi~_)k#-N5izNy0%(q7hMm?oL_Ju8jMFGA9bKb zv$!gbC9lC0>Unx?+*3GF(6ZZH<(4j|5-Om02Y2z2IG_&xn+2Z`6;N1An(~^lQwwUQ zOiKj)?fuj7EGlb8nv@wDs4us&o=Bt%l*TAhB{h=R+Pddpm83-ms{V0T&ofYt=D7dS=Kr=V{~wzR|1=j_+3Fh+3mcp0J6k#Z&$+yVt*OJ$s$BYK zRx!5u|IH#%N;9@dV#r@$o(;Dy3GBon{2-)SK+R!>`0yL(nq~lFeelQy_)_BZt2i}m z8rSXb0|MpaMQpG<_IaUCD@=+=`KtLmC}H1)-vV;8Y!fw&`K2B6oou$QOj%XL`Ye$dX*5~GV? zjoCc8{4m*B_lFn=K@#mp@(*Vga>;sjA3Ds|(a_aGGbuFi)9-z>)&hY^h=PM>jvvAt z$Q7Zfbr%lPeu2OFHW3uNyavs`ezAXnB`OuCGx+U1e%!gwF?S3T3XLaG+BzOfiLB-f zLsTI!R2nT{#3)Z+EHpqiKXE$CK-~2S!*Tvgi)l{*o7SZiuHQf&N=jK$gt6|+nF)`Gm z!Txq?dNfctW^}=z-436nDud8w974=Iuf~cqED93ykXqf1w8FZK9fiO>iyHhGH6`Xa zy99CYP)x3@)FSqPdVt-Br1$H%x6;EwpuBzZ?#_D^RUI0KPMzf^_Q2rPhK)0jFB8Xm zlV*;2seylEHqM|s4!E5>k-zx$17R0R2*LcwM(ea^%K>Rf92id$mc6SChy+Lhh?+zh zvO6({dx7GOFjsuW1#TIks9C3Y1NS^K;IL#Bmt5WRAnNcc>QhlO{Vj2vmon)s*asQd z33&IEDekAAXHibwHHW4Kjin6FB;UgbL))#+*%fRgjq!Uy)J$xt^A4P* z=wpGU$DPMXW)DL%DW!nu39E+G5tKB@YM$r#?rOf~PwEaIWOZ?-rZteokPGZsqWYS4;B z|0LjjIbp)2Q9#;HApIi0rAAv&MKYgXU3KhsoOYe|YT)zr{({<}EXL67@nFgE$g8n) zlwsHK7H3m?1l)9j7MVEeKIFU&$Urel=||l_I+%2%vpEWGJ4%Ae=4~9emV-GN((dey zu%{X&7)-JZ@$2L0Yqtni7;-H%fWs%8= z=kT2S6oOA<-_q!hTShh=6tYB`my{cf^+Lx>yzS~3hAy^=8Fn4^M9*a;F$7-pPb`5WTTi>BH<(hQt<2d>L}bEO@qeR~R5CV6M#}U~hOs$t?sI z7o&N-naKA!$TJ z>&^XTo(>zGjv|b*XTI$ut5?7&&KtRH*Xif1`>gBEp7*Joo(B{{&6%EYr?;2euFLC6 zyxINGDCvA&Z9Ke6+p?I9Q!BMcUI`b0h}(?yqWH@VsM zQOR!?^5j*fLK3_B=$34i3+r{u7IgD)M~W2q7y3L-307k;BupXtBuqlRxD3=-rhwa9 z?bS^@iS*Hnd^;p2cOp}nC~VDSN?;3$3z!yI^$)`1W?UAhtCjjqn>M&ph0;8EaiL{z zu|C4KQm1Ko&6~iXk*x&^ph_a+*qDsevtmcT;T0k>1Tvc@2_|YU#phijBjGm~(FAS> zlUlF>J!lV+cX^mbgNt|q+%c)}o#I2L8tL)BII4PpHABevx1oqq4Fk=enLf)lPJppehzt;iO9UQ2qK{ycJZ}25$Em8#QCj@IGeY)Ih;t1C_j5#Indn9> z?q%Mr*&t<`FGYDnXUw!Q9F(&(vc=j2NyA|}`{O%(aBk4&ic|F*CyG^zcJTh7Jbkku znj-MdZ0aPz3?=kXncCW=-<;dP;J9T1y-C;{aJj^)J(P2N6H-0wO?ZvS=U!GHKVCK< z=aWv?u%5>H&8MwXa49`eLmGW<%;nt}*#2=)K*`axE(dLvH|fGa6F34#8tRY?cr_y0 ze3Ys0rp;JgADiP65s|!r+v;Bhhv}`Vm{n>M24Hc%zOJ&UhG2A;(vSJbsM4>fU{u2_ z-6VIhEcV`qxROML_k8tmxBr)-{ z0Nki4Ka!>@`U^UZ)eJ*+dVEKh%hU52puWKbEG44AD>zWsBPQobQCa)OTlz41wS`U5 zA(_e!#MIkQ_D?<^L@2G~TpSiQGc{2i*D?M}9=ed6<%52)rPN_&_Zz}kJyQ*xrss+n z+*}R)Uzw_8MN}8>Nin$jkrHrz;R3n*HT*JD&M9fIRS?wRHq#A#i(f4q5+z;_5Ij)k z55fi>(u^$A=GCiS!o_k6hWVWf;@9>(C^LB-^lw%JYn+7v`}UC04jw=#dbI?>PxGb< z^hYM;a|^$Xv8HwRyEFBlC0EGDeVFD zsI=F15ChE=aHP6tL~Ao9#WHh`H@ZcicgWiJi5Wg12JkaFg6%fLuw^#2^+FGSBYJC) zcLQaBfXhJJeIf<*h>U>kVP9*cRCfKc<$@qO~wd*)<>-)SK6P zJ@I^4#us1Hf$yt#&=?VaIkhDY^^W;!&OFd#L5S3wEK(42b#OVRSI3Yn=DLC>djb3m zOx*FMX7ymI4;B56>=L7Cv?Opmx_j#kUAIX{b-S2c8Z$v=gOMvo?-ij^Qg7+-IsiMdRFM)v7G{O9O zb{zD!lmDA*H)}70ZFQ4xTkLM$F*jknM@CK!9fA;1rEyA1T;kT|rRhl7MQ@3Z8K3<$ zthbXo^c6w1sy3usEhrD|+wtJ{DqW>!SzzMAYG&n5P_48!FI7^!mt^UsJ=Ii%VFz|f zC`{_0n8zVxPB%8P&U9wpG3=awF3lq(pY)ZY+X0iPX>u?nXvOVKqHlZ!kPr!p?==9sB_~DS`Wz) z-C{l?ZU7>v`xhem*b=STWhZXwe7a@WUN>CeYu(sj2^yMe+X__p(O0XKfx z%AXEQxVFsfTzy)ozm#eCQhr*;4iF$jVCn@40VgXeH%1E z29UQ3y$aVZ3TOp-E~*g`Gz^slv`Lf|RO$MFBa@P)tKRuI=cc?XxIqzmXgmw~OWv_3 z79M~sk*g{jtNxD4ShkFGO@d3`N{)-(L`+B$P3o{T)|L%BE`c71nj=koezdtBY4~a%t^5r3-m!3Kj%V`9dB?v%w?BxOI$&~!jUNWa z@o8Q~I6n%f3*aDLLYK<|4FU2X@*``7jnlDRq5+VebLwb4vJVL_1XDYFTUc;$dW3relP0}p?81NZ&{!uRJU{&9)O%uEL4Mkts~ z&T=;)Kjl_c^Tc3YX*8y9Lb`*cpyU^wFHkn{Z--k1SA~|n0bO2_YwyEVv91paW(>>D z5A?fn$`0!!94mEWTUFmE5+yocu&wZDj;aE3+jOFJ95*T%`pKWaqKNiaixt!T^#`@p zHlA$6Fj^5&7!Hb19 zHyE9zQWe<12XmH)8IDIOtwPeM zHRd&LKn-qMRQRtyy5LYzR9#*8JDBD2K-E^^INa=#S{XA+rW5XKtg>7Nn^Of&Vhir! z+P>KycTUF|e~Hw_vAX%ap<+u9o9)jcAVaw~|4zkmS zZa8>nl~i|D8zjQ^%<{;ZR6cbVD>%?nlBzUD&(9h}VOpBkVW!AuVW!MGuz;OfTWE_| z{yi!0mE#74$DH%4$iv357s-5PS(g3aXJUS?=I-+Jz4Y{Czu2{VMepL1!wV0l8b0k) zSH~&|HJ~YYm{WKY&gKO*WNzB=l|JE3C?T`VIh$Fi$wHFx68QWYRy%ziF%z4Zc<{>B zjkGSyv*i{+F*O@tKQ!EDM%7xw!z{Yx)~Woo$kr{Z7+t7ve;X$MoE{R-LVe22TZY;% zOIFYRqSw}4;Mcno^z?O*G8Q`&wbgNV%>E*DX{fnqK*lP#K0dvcU3endLW%GugLOH< z>Y{oG#ECe$UPvO#$t@?@GA5JFE*6oY@?+$jRxnx(BiZ8q{AuRkwymR+;{*D6-bh*) z-5@PC8lo`?K**Ec9*n$U>OJRjK0H$J@vnMoQZa4ti zMegzJ2oft=1Y+aEG$4JE9{t_I{tH*SwKVixk$IyL|hvQq*qu&_4C6X zp>36)v+qAXl|OfXL8koN-RrhNjjA36)N;pjmTkOO>jg}c>35j<2gH)fb7QYv#8VV2-AXJ1-O{Vpi$uIz3lMp3dl`?Wwpp>|6_$}|ROmbQ- z+O3VID2pdMNR%dc(_#%+-P-%bNIb5Irk&d>rOY(_mq8%P;dkWuH0mR4vhl=r?rV5g z%=n2Yz2%@f5#I6!(KxF>D%1-3IyJU|VW-!(l$}cWBQtobb>#9D+>HlD>@kp+qgiCj zU_Y+2nP+9m^gw~vIRygs?R~aXBZ*Vk8cFZj_&b8(pTaY{Y}cTT z*fRuKeL3=89rk16#2TNQ%KL}Ryx)%5M0MHy=A(uL9M*f_;^wBL-FO~J+@|(7I)GQF zGxu8y$fzRDE)xoI0MCR3S^FKd3Mzir$&35HZu)9V$~5*Kk^r{%vt!7ISD#%fswRS1 z7x8ugQ&u(usOPXbN5Z5URhEFc|NLc;g}f4JzVjlUxu&$T#yH-Omy4s=$~b=B<)v}= z;R7RHY}oe#TExRVjM2_)jF*Q3%G{)3ZZqgSTa^}wnjk_InITrx)tW> zN_A5pLZ9CogVv`5^1_9Jm_n4I&Od-1kC6YSPp-Oxyt0!D zIplg&zC_?4NKvoQui_?BUY3EYOP5n0W0#hYf21a%4Fg1xeEs;w-CE2d_X6pd9A`2e zuiIRY)}Lqe0J(eXdpq{`UG}5w@h=I2qwDlnybY&n3-F)3(mWK*z~Y1=sqQ352UCF4 zQlI=T^y5Lp>gG~>1T94`()}Z4=w<|*zIWTL=+#(!PT$k6nPOoI-RVk#s?iWB=$tTc z;v`#9_oLoCy7W1j8Mn^hfr?}kDKcERb3jxH4>hafqve(?N%m6{o48;*Aj`VQb5)Ul zHK-31_Fm*+OH8EXSzh8{$7fljqN=ahTv<75(Rp-SR$Zz#EMGFOcXfT5%J^HHx8x@r zP2)nIWHes~>%OVy%4>O3(0{X?N*ukyQv5>kKb>M|32-D&p%1(V8j7s?3w|Lp63nOV z937ts^a~AioVI92W$?353}~XMK~{A}5JkKH5b=n9Ciq@IDBAB;Z!IUAV+ciiDvH*j zMD^3Dk+a${QM5$azio{#f^OHOx>LnJ+5kbRm4^N`5ii4(4>XD|b?3s1jrWv1Z}MFy zT9v+!?Ds9SiLUpcRnr?JG+C=^SKkC=BwXt~F8Tyir)=)czcAl$Z)2R5pR!H;e=OVl z8*}D=$~ONscK(|=^G~^sSitaqkw<2U?vov$hY7)fa=I8~62|7IuK10w(qZq9BnSjK zt$S9yI^QU{77(-&cteiu27n8-8*tNC&-dMPS#upD2hi$Q=J$O0#Os?xwTN{WtSzZC zp0+5nsTrDO-C3RykP7Y)6z8U{uiQ@973Pg|STBrbPO4R4VU>jA3ZJD%OK)mD`u%Bq zjUA|-$B9L(11X}nY*naJ%@8ESe`WsFWU8vR= z2;2}9@)$?_zbc_riw26%Kg!e8Kd<=z-OEDxpIr0*^LqcyFQ+uzy_6rD_)MF*+Au)L zK+sV!gc8RX!}1A93BeHY86igj>{s@tCS@2Inb@Wg|3Ir$G(TxPHZ`*>y-_zsskEEv zlcqu`YL%;Yn6XuOyEIg6vQ;HLymz>grb&Gw(*q#A5?6USh=@|D2=%(`I*cmsk7f^9^}}P? z?OW5EW$5ivagZURMyiQ!)dSTd0?Cq6Pu{r&OKRfiuu+&nj(M|bhppFk4ze_}sSz1;);PvKNiaE=q^G|5w^Vy2SN zBs0Xts91C^d0dq<=JmXesd8D;1K5UvF9?WTYl6d%lJqXxN`Pj}5LxPgSRE$%)Se9Nn;^;MLmXCiH$)23AiNRlj3 zB5S`@U11=y{xj(rqgS3zSUD^dhUILAwb|IZt>UN#gv=Rm63ig{MK*6HQPQQC{?1ODO*flB7}Q(AO3hFI}(g&O+0tS_v* zssss=fjAF6c7M%h{bJFcbm>-<=R>Xa4X{qGb3|a97zk+R8pO+p(k2^QM<;%(sz0y~ zRB?%#!Lct8vXEtAzqvF2#xo$NsieLB9TCSs^E_?X{@2BD7<@uv#vvJzQhJD^v3!dT zl|$vIA|g+p5nMz|Au5{UAyp|$2kfI)S~hhN0%yOnr(#(o-&bKg$Y+VeF{*sx3Du~N znZWwrE{QHx{GA?2J*uLTQ+AKA)Nbt+N2AXvftlF`pev3SOJ$4`MSDf=HiGkA5i0UO zd~$T7PLbVXMt2^U57wmD5}@X1U>&QO#B&jZ0J18_+exP+Z@5Me9xd0Jbq&L^e7(>X zNNZ(5fx4(0i?cEE=!j+2!b@EfJXIo&j};GwfS*019h#N=Yt|*|0J4`!D5 zN_q7;3^d-)FNmK&7&H^rwGK+yh}q{Hpt?|PFC?Fm#mlG5xknmlrQ>IgB05c3KF~=a zh6K*nAvP~CiOXlXY$wlxYQ8_)WN;>NeiQS5Mb-&Nuox?GER-8$-`li(QhmzUy}Keq zW@+_RPM`C|bx|r{2{VLpv4kQKehI>QOprT%3zknCxVb_F`5u!3W#trOn>06Z6D*XH z=M)M2!jWK4RGLfuttE%E2P@F6hVZljI&jmjn43^ zPJ~{D)br75_H1XB8(ej-Emk3-$#Qk8x9>hEB<9vjxJQ=EG&)&*v=3TD&pvVnxeR-) z?Lb+YlOky39f%jYERz8;%h7@zQH?O%8>!r^nUZ(>IPqq+lbCHA8Ax24#IZ@dwzGe_ zNr{+ocSoD-L2*Xdg%@t^OiJbgq#@1W&4(>T_SLJKpM5HrJSQaRRfbG&uyI9+T~>My zyWR{C12~~%bhg$$vJk%xRx<*^v~v)B^3%hV33i~-tUvA5Sfb|5i=rmc9n>)2!GqKa z^P&<_F>DtK$|77CJ5xuKX-Q%!OtxP3n%EsDQrn82M%6F*?l55XtzSVcMPQG0ZuQjl zmq*Ic&aackwk$S6PqbQ!TT;VJDSX~x&h0RoXfrD8&a{@qUZfVn6$ilU9V(GVzCpk^ zP$Zf;Ui%dnVGK2;ueF6kZ zFhW{mY7j^Tftei%owFtP`AO&4M?tOT( z;Htw$hS6rDA9#f<0l{2DA~U)NOfScqg!^m^q#5Caibizsnh)JfGIIAiSiC=S%J|_X-AWeS|ich7A5v3!>zaS0qG@+}6 zF+61ADkXR}zFbZ1mX?PdOp=@C9DI^|;2Tz^0qedK3>_4z?WYMY85qL(rt=Zq14q`G zmX)L~hGa0K_F1zeK5O`YjYkt&x-#C=rX%}-v%xC}Z95zssU#Mk{YR8Je z@U4Wha=tl!xo6aPg=VsfWT-Uw*s!bATd!Jrcam6JES#?b>09?3j3HtW9zjdZo{@vm z;Qsw!K~TU*LK!uvRJbS;OkNH2Wt%Y^x3I4&v!zodO!!r6#`%hm7yl~tBXG|sE%(t= zztYj^vC$ivB^+7S$l7s@do8-L_omu&g;hi4Q7^#p%DB);DAqKLC_yf{M--fbVCW4Q zpLSAJpyR=Jw|FpZ7!OY9&`o&H;FE5C-006%H7z?V^+c?EUl19l4m+%pxM%W-d$e~- zt(|&Ex@CFK^ihfbnmM|@OUuO+x=YOaa6Up`MZSv=z+ zj&v;Xfs>|(JoZyyf*n#2H&qEvkEBqz1th01TIY?cy1siJEZd%upf04|88q_e^UcqIJI$qO^tX{0Q=;ytn*d0;d>W zpbMg2hvsXQ_P18QOkwPq?4dM+V|(uRBPZ<<$bpw08v0vS$9$VUpbm=Fv(IMqMe~ij zM>0rOq>iZMoC}d%y?jB;97(AMLyv&6Zzi(5LIvB?<#Ywf0)mZ_~Rdangdl z&@8jcCHuwoEo63_;{rqY2HFx=n@YZylX9a} zl&P9Yv{)Lgc|b3Q1o2l|SANshLidoYfmF5?I`bsF`E$9kGP};}K?$qva#L^~CH` z!TFGfb4WF(Bq_ENC#V_OREgx>tR!Qa(Jg2?b%7g;M5AE-&>&(JHfZkcmN2s4eJeN!nCrcl9Way`gTk=o|nGo|BD1pGHLvB0ih$H-WM^@K##RBrgEQ`4$CSNzg z8QjInTy|bpvXE2PqeM9*$mGvZ!Ps7Fn?$@*V_0OIlsGq$7xq#m0A&oC)8WX5OB{I{& z&m4D92ULj=J&5P>4A>lRn(KPS@|aiq-&TfHnOC`uYpkgbZ!za!sgrKX&HmC&DR$Qw znLUwmqe#(ab!;OBsne)NG--Cm>qV#<+25uf(vCyt?AGIMoJse#4t}n3bFn42(girok)X zsLlF0m3f3uPV@^VjN3J zs7vW$dREOUH=t;vnxK-_6qp*ejG&zM*m*>v9wu&xniWe@+eJ-67VZtoVET-b0X5{6 zr(c*Y=7z@KB`=B#zMR8)M_(&sn@t?LtNkyD`lrk0nJapT+`Ued`PVEyOY{v7f2Alh zxP{mY>C3kmqt~@Sx9=weAH3PUD&9e;-4Z?DM%u2JrA~7?nOo3Fg!@?ilHRb~Q9Vh0 zS~k)vttP$Xy9A>{?$-j{oKIM^!~^qOk9nFfO9U;uX<{Z}MGPU&T0}pPw4d7EHF*^c z(1Qo888T#p5hW(|Q-(yg#r6vVzhg0gpd>56bb9oH0wu}%3M)p2fxFLEy>QG4R_-h8 zU+Al?!eBv?3%sHzLA?4>j0E@%7$S|RYf_S$ylY+ z4n%*ot_mG#p83HvVERPUjJRH!Ay-9T%yQe2biJr+b%|?XeE(`??bZyWEqp{h5`F<$ z|26&q>X&o$0crC>TI-zNN~}*w7-kFnefLs z2fQs{{%-wM-9ryBgJ*Iuv&{5yuKy+Eoc^si>??Jju|gyAn_Uf`ajXB1%g`EBtwiQ1 zx^awk%lc*V?-yf2mx&<2oHk?3d{TaxpMu&Sc>d+t2h>+*DNg;iw%P+Pbq56MHt1{8 zuC!j;1YlpBL2hXi-rks7|L=db0Mz7?nWiEF08stMZRP$Sn6!kAqm#as74d%`|J5u1 zZ`hY{-1iNNl z1=2bj@r1^~3~TeQTAAId%fY2ha|!FRU6VMpiAkkk@VViqVwhBxz8SBI0v70InyyD6 z3Bn|Jj3nVomoatTh{xa7jx;yvi_UnW_#l*M<|9E)rOc4j#iVycL>cKHTtp3#k-nKL z+7?|mS#aSINetxl?nE8)%Zyk>!C1k`<{`huyPwZD2`YbK4!99|Okznl56^r1}88nU&cpyn*~f zRP2FGaX0@#FpvKuii!WfqnQ6~#DBA2l_uoxjK6W&?wmdns)%IKg2?m;9KE4d3H+J4 z{P-@21_oU4WQ76zv4`7rf2c8VBqkLlTWX8sn;VP7*r9$|Zvr<123Vyh&st-dNnOt) zxtL4AjW-w3bde9fPrdt&)f0toUJ2&UdD?Duy5Ap7dEF=0V82i93p+Kxkri{*^!QAa z`)V#?MO?Egc}EaN?0rV`N9>*U}noU~6E-WouZiR;Mgh z;i}OVBurvrDpRj7!i%ICbMj)VT&(w5JB7dEWs8$MSfbZaa1D^jw$rlh41JSI!*+g5 zc`HjldKt~dEdKiq-t`OW#SHiFi#h4kU3|pR`S;CF5SvpIp|Cl8#>|qEO zL6o_yj`uN0$wSqXQfj)_qWIKrnS3$j-u8y`GrF8k5xy*m3E_xC>4xG+3@28lsi2dl zG->G?bNPxG)$u+RlKOK*4722EnDvKFTfCP}MVn#i1AP7T_HVVXeMTs4JO zpT_!OPG@)cEQ+es9a7Q~8ZJxuwg`RN6PqI_ZGrR{=g#vc28nWQy+I8dcb5dFR^-u; z&&P%sTVJJ;F`R;9s*$hDbF31St>mkHWdp=P*}5fF!x?lQhPw$TMi}e=#xDm^PWJok zBklIX+F!cN8)z!@No~Er@9ywmEwj?-&7I}xh?Aw0SPtK(3EQ+5LHqwwu+}k1p;#vH zrvh`dw3QgL-4@kIQ!Av--?{@#~s8|+dQ;(;Mo#ndpY6spn{3TJBv8{Ee0%vgX2)N zCCV1=Y(p9TH+hpYR^mG9QF6nF>tHb9wDPpXRlL7F+QvVV*IK(W=+D|wiR-*I;elS7 zY`O=x^{a5b-2CDtug6c%+y!Jb>;Y$1|5k+KbP-$ndnLz+PK~0IJ6_kenCmP!NG!nT z0oX@l4sD#DBU$@kjnc{sh4baeOf!mqY{x0?+@X-P%tFTkGt+fK8Xnl}SW!g#bX7&^ z+2;eo?q}&im*rirs}E*eubvzp8ZZ##(eDL0O^$sfaX!0;rmj^d#vG<0v5$vbadqkM z;c@S>jXq)Rz%lvuo_XtEk0U!0-X%0LG%_Oo&y;sC!y!Vzbv!1e%gjo7+E(!P5CXQg zglw~&%zv|GAITU4^EUXYL*ba5L|+fG{n2f#<$P`;XXQzw!rFG>1xIQtjYXPCx$0Tg z_y1H9*k8*NMu;cG(T9I5k|_z+!6-KvLctWLG?awCF`Wto6>5{_B*kX_J!#TlRfW|Q zTxT2;H#0}=YR;55U1N;$dTp5H%;k}GCmbbyfA00QK5!SnK;wWT_=y7G3YX(F_2ej zekKG-;-FFYlnsInfBS-ue-l(=JyzlnCV;dv+bFa!pd>$1xZyr37BgGGzr|0+^O~0j z15^}t&e-E6dU|#)QNVmuka5beLq1^$=n5hx6Mg@fLV!rjf(f07zjUyE!{MRr^$O81 z9c&-SdtEZ{pn(T}h6ZnUS7wPMBn?d!5HMe!BHRBbb05=@24O?2h_`+1 zSkky=Y6p<;hK&MFs_UV3Pi4-ZFlQ5qOdAaJ4>=1O04Q<~*!bCF?FPS~o{er4?b z@BAktYAQF=_~SF#TF%vAsN~HdgBetV+7Sn}tl<@KS7SOg0f&fC(;da%oL1YWSL+*m zGM#5P_te#*^#`lcd2E#Bzrd<*Ozyihcs6GM{UIN@;iOnS-MRs~qr?3IfIIow<-ibm z1axfeXk3WdOtrvL9~RrkL@RPE27Wm{vO5xg=Y{Si6xRMyB}nHWVL(7VUs(tiyCf+=eFX z^v*e{k1Tj6MkZdZ0LiaYY^zFpCUo+Dxx=bBlNeU*IS#VeeOAzI)Vt^$zh$j^EZMHM z**h+Kz~xZ6N@mz-#ETTbxO`K|Nr-N;@=2jQ#7ZgkFx(W;GWygjB|Jx@jU+qS`t!IrL_@Mh#X_TZx%@ z^4p_*L+-*ol_Bw(5gpCY^}j0qLkVl4eKqJivQEuSwK~_wQU=a?(Pr}B&EB% zySux)K|s1&x?55}O1is2>5>k~O$h(?yyyFj*W>Z~9|mI&_Fz2Mnsd!nbFSyU4NmP* zk_r34gxePNOJ$h6cykvyCw$qW0>}3|r&9U*AFcQWu@^Z90;YM#zVCO^+rx zNH@pXoqevqr|SqP@$wvXr8J@&d_JP>=uXmMSW8G@sN0shx}NXhJ^U;k3^P3*Y9*{X zT_){Q>`WUL%w79gi?=u4Dq=QB^rnC>Qexc!1mCKET58qi_4>ylhJterN@VVP&{9R} zf`VGjgzL=<92XlYXsi4V{!C1%tpasaKFas6LJV)K-=vfm;P_v(pq!FX4Y?&YsVKhO zR%%faHzRDbQ!M3E;64T2WnRzcuczPxKYjJ4E?oK+r6|}!&xa}zY4)CB2A?|sZ9Z0a z|7}5bo3I!eu5axh5J}j*49lzaa_Zc8rw3g>pdb(cSDK@($H8DyJ~4-_*`cwZ$s? ze5h6-?o%Yb`5-tXa|0?FF6Y2tk6?PhbB~VSfa6cTW01)6;9^4dE+jka44m<(+qOx| zS7+%A4{cV1vYAlL_6DE@7TAVxXLfPEJy)0APHnPc=nL6sYxCkc(#=FY#J=VU)@bgA z0_~_L;7&Dz1PtGWxfn&<4}Ma94p>_udw=f*7k4kv58VQ0lC!J^kehlmGtWV4Mi6UiYHz1L*lE`k@;g5_yK$-= zZtu<-NFGqxlm4JpB#T7g%Ex-iNmQO!&y7g$cHfwbO|=&7md}4l4Mn9|n24rEQ^>Ux zYO+gTedMAD(2~_1Q6k*FOpy38A*yn7gLcbXj?+s+U;2tl$BG4xn$@hHmfNzSfuA*V zDR8OI{FbT?yi6r34Q}@hSTAGKo2ggB19-#DmV2x|Zadz2|rHCQV8f=qYq3S-XQKr)V!L{fbjC(JB{i1oZ ziF#JsGKmxT>@0|5a3}*}b2#dWUIr!i`8n>4;r7E*)&qvB!SvEbZkC%_T$i>HF_iTK znSw(apn9nYdcK)KaXd!E__$?es}T}>(H*ztldjGo3~FxJOQHIwDEbA;V7L2u0y+iR zI z`Ta|+1SVzj1fro-ACvhOxw!`lkeVnt+5zUv+2Q>l6W3DEHS!?GkLeUc=jF=*DYi;4 zgAmXvqwtL98S&@oBP*(OL2;6Q!{jJ!x!SIzc(UKP=n25KVnzea3MJKb=3u8Cm>iLlc zo>?@$-95+WQf~)EAZt_5R=Kx&-+eesXf5(h%iWVsgV-k<5sR4Bt?SzA!_Si!Vs17{ z{6tvfF)5Sptk|88Zta~Yi^wNgFB3D>72<4rA$j}O^elvaJgTjo4ShF~YmiNpHeGbr zyKXGp)-!&Ibd!z^zbI+4QbF?)fGbwcwDyLFza9Z}=ghoEC1>_-5DRf*_-4`0`D_3% z-j$9^NUELnMfu|?&hgFGHu3n@;Oi!chfyGFC1tj zysM2L<;pVB&eZILeivP-DG6^E!_0P@Pv$*0)yMcNP8S ztipdgy#t~iDVyOeruzZb?;xzt0NZ53utk9^3ZvN}(iFQco`XI5+!2~Bt*g7s$UI9V zqTk}E=N|5KTZK~u!6+3ngR++0rc2UcL~b2^1ySOpH^5EkBa;19dk^IoLT_D(^eYV? zh)u!~KjQmm97L8GO!T6q$6zM-+4)P@I(QCal||#8B$YWzh+EnD6~{;lGD;KM(2Z~x zbfm^>#(c>3<`9QS(Mb$0_NoT37Om8`p*ft5u4+)-eY&scXqIdG8ph(=r%k3w~PVLOXd zvY%SJgzTUS)}20bSmIE#Ku2ArE#^+hFkz~5s)Jq}y~;DcyBxahE*PlD`+}A(u^rn<&8zczVDn%^A5dk-Vy_mr0qL*uM z+kH(G>dhnCDc>o`r?(AIs+^*rfe)ECTkV3CYD3Q#19fXQhe<>BD4P`WFJ{4fglrGp zMC#o(hLNzR_6BG%EOWFS0kBYlhLR^aX`ly0}L;y&ATq9Kgir+g(JSTR7eC^Kd70rtk@Qwh@u3M8?jc zvgkQ+ER2q@6iY?Es?2yUOPXy52HHmmw09OlCy8i1JSX$cFQ?Kz?WxLaD*;xXXdOZ= zBkjariS2=U=4{ztOD4WdLby%7@-N=%81G7r_onmAC}*~wh&dH`ElcXAaT1YCg!*3c zydPyIQxoLY1}B)t!AYV-sVm|=v@yqXQI~?W4Le?d1`+uZEGOQ|ee*VGf zrT|&74wW?}lFB{`V02N9RseY6=RHwR+vczuOFPU6KW$IutXl`cwNkIGa12qG zrJ%bP3TNk7J?}yS3x6XEWxoN1EKl;n-Jr)OR82@8A-lLcqJ0m!DhivFnJu)P!CIZozRj3Dupfu>UuxP6njtRWN0x(t)#GPjJ(W*QX;@KZebajIc;dm zCW~hL0jRsrD=aVq-P|3Oy{?-lW2lzd!ihrjVFr)oLbOS5oQOiE*S-!;?Lbx&bB@wB zIBCNkoH#5Y8I#5PlHx>EpLUEIfBnTV;pU3R%nfkZ z!YFhE-!>M@7lKEDX})s?nHWmd;*DDNM6GEm7PaY{ePtQ7vU*E6^Yo7t_xmKXg?pIw zLetbL($kGYR?TwDFJ{6?y@??DP->A;k*WI-u5h`r_Fj=a1?c8CaYv_fx+w3Y&sz)# z5l!Eerg8T>?FtY$ym)%@xf}a@V)bx@rCghzp-=;#(K|s@NOO*IZA)NzB23n8Oyp`N z6Y_)!pjq5GpOl;|9mspLVAjuk4Swf>dB>Z+oWGfksTiJHt6LL8{)`TN&}5mlo&S@f zn?k$j;4E88b8ms}U06xznINvR%znonws$*X0nXu~KR;D&0=; zq1MxLBj~1VFmZ3_rpJ&0B|edG0LL4z$TA%JtOE-~IHfCXompV+wy z8-&6rt-RaR;6BG2HZ5IoYkQ!W1K80!*5H1C5|T&@US7!VmLWU9nG%2IR0sf%g(q;p zir%R2#OCiM-FRbfu?u|_l)-Q7I{}F_K#B)nXF9wXSLm-9xO`&}clEL58GaMK6`1Uo zQKob~3zs=o{h-kD;27bhfCkdw{8=X?mD$rB(iIfJLV2z}Inma$btemM>{3VY_dH`c zRmH*W_;0{4Bi*0y!=kq3gCg}!KzsqQv(?<&2%Y|52_E_JZZE7axCF6;pWKz-h9;(1 zFEg|lBDp{TkLtU9pc8X{8!)$h;lT}wYiX`cFvH{sCC$IJ1nrkGsX1R-c54t zLc9jBHVaK(PZqQAK)*w|rQxaCi@4yDsR;BKp_0+QMY4^V@oQdty=y?g5jigp7$EqZ zjDUR~x@7qfAlguTFi<0JZx{E(?05$3ZrE!(`+7JwC(6-O)0zPfL-;9#k~GMZLtGy?nM#)>2+T`kNj ze-Cd%!Vd{3rx0cOIo+1L-plN7F!@)*0?vWum?{xsvwILKF<=UycOWzqNrt^1DAHo{ z&>l4+Ab^}}aY{#leq4;cq6#<-V$Ho7UKVZ81@Wh+CFOY)SxBEZUOMd5^n&4mJBI5y zhiL&%RP$EK=dU%dsx>v_%dKWSAnH{~OU>To6_twC8@+RTFwOV zjN#5sZh{G`WWFrn$+vV8xa_EdxGegTh$iG5fdf8|IkR2eF_u{^F!2%tv7EYty{ytY zfTzxF4)ngPoP_WTG|Fer08u&Q$%>o}_7yWw_VUke{^I-nDIPLL`#{~ep5)0hW*8ez z$=vvIc7ys0bTt^Z4cC$pSAr8jP+)*}S0n5;J4~41b{%cIM*fv_$1_a{7~CzEGF*%a zmo!~DyV(mH=a!>N6aTXY|l>8fd_G+w#(nF|q5jcLBA z13?#dl>PPCA}RNzqD6oVO(@OKym{I-Pa5JmLRwqW$FBiUBnL+P2)@~J(ec|s_sm!R2@$OKicGYN*2GqU(J&T z{Lqn)*=vxuAX1Gv0Dk!C`pCTtlDrGq_gKcHI?^jian>rS^UL?G0{-ilaNK#DTyw56 z{Mo5FbQ?Hew~5Kllovle5o!-n7?EA%~9 z%jQnBip8H@%a9KGo;gZW59-6s%P>_Y62@fk&z9tt_3vec<8wZNl}y-DPVJOG|Iin_ z626Fx(_8z21@R?Y6h3=m$wyZ(m0~u^gGm$C_>_E9bIWd}w}}Fi6`vO0&SEgSdVWB! z70oGSTwI5)%Dq)n3w0Upp_=|g;_;3OZw=}>WJUsdX*M=A4EsAwYD>0ZPrKc^Y`%(P zR4QJgyJNu4aNup&3279U6_ zdbsfLmw#jb+-(ai0SJf=$M4ESh--^XS307Zgwt`pJ8{}aNm%u@LRcdGx zw~H)F7#NIpX{7#kW5V(1H5 zz5AdL#5;!Xs~elu2h{fX{pR6_V=3+&^ruJ{iTx$`s^O_)RYD@?{ol+}(o43PDCFcy z>6@z&ig(9lnQ&Je#^YG*qG0nV5izc-nDi1Oya!vptC5L&xq!LbWas62!Jk9@Hgg$u zcf|NzytpAfC_?Eo)ZG&ywyD+)KyrtAk@F|5=o#Mda4t2W8yW1la)U@5zE9jn2t8L( zX81%5B2%>F4iIQQ*!=|^;t?PSN?@8gFwrSJ@S3$#y8xt&xUbuD-u=7}9#eLWR72-qTT@xu+BTcA6}iClYMq3D|3PS&w~_olnHK zbbUG}X3XIIUV2VpcbYSqR^lWK`E;G4pb|N_JYdhO-P9g;3Pq zx#XGZHE!5Xc?m~}&3$AbIXJZLI=xQV><&VT5CXbQ&*Kz10ue(bo$2A61QOcN*>`p;EOKRNXLPtn*{8w3F-Cleb(>;Dq;Q;C(4 zd?J7xq=(1C&}V+H(IjuWE!QWIPhSF^7YZk!fUfOIo+QzqwU^5k7P>3Y8U%-;?GA!O zHYcntF5ohIP^By2K2uO|W-gA~czK@O*61M(U{K*rXX`j+=FR!L5*bC z8%ZNoC}V;XL!Kpb>sP)JkSj_sf;rwMx2$<+g%bK77T7~8tSw-VD@GV=JA)2g5Hs@& zN(X^2sMAj;J;5fpbBvQ$s%Wr@mKo`t|+60qbQv%_fRc(1N8*2fDS zc~Y)?i3pyo`Y`?2GK=TmHMB1Sk?@)-KhzR}Oj=qWo(Ut-uUx}_lC%xNatZzBfmEBJ zSB2ILfPtS-VxP5RivoeD?|F1}MKFC}S2DXwe+>&i*)@^(pNc<0Ylm@t;ENoizkQkG z#jnpbKyf#qNVcsT*VPwT{GWW9AfDFmg(z^eN2;&JR3~wRYIg?8~`b z6w+Q}ETeZ#j>1Z?z5425VK$AnXI=J;)o?YW1AC@*n=7rc0xy8rmLo~Jcb!bgn3ceG zv1@S2g~rpP*}ia;hD~CRV%Kn2XA_Ux$o_4-22CZ*sM5r!eGy6Peeyw==5WHgAUBr! zfvRYibkq^Pj~pB0`BIi)Xx#xu3H)+%OM`sS+HY@3+2tFUh{#~*CgyA#2A6>lqfn z6S5O{6{Wk3D3`MS+HG^VfwulGBaN;h`#huNIg<4%zjQE;0edb^GBt_26eM9Eg~2<= z%x&8wNd;sz2J(b`T`Vn+b%GZu!pg_&@u44I_b|jc_M^Ast*GX% z~cER`C{E`DzN*%y4r>@ti4A$Le2~6EEK|BE&%nFopIQQ zN!-D9pX<=ija}?3M}Wur)SnR4!Q^=N{TZI>K-5OX+PuZ@ecEdP)O|3 z;Z49IgbEtgSJg(*(Aa^$Aoi=5ZV6^_E4HzP)mn?bbRzqSk-Q@}P! zU^@l7uS{R0FQ1#*uh%#!jP+VDBI7|deK+xz-o;cMwsFQa_N6oU`m|HL^uTLD=QXI? zqFiDND9*>fT!W9Zuh{5;R})jH-(6Au;dQ~kD`bIM)20??E{+DjC_(m7K9a=~L+3%m zmtNX7LSUw(wb78YdD4gQYKDwb0w6BK=Xyc%RRPAvWSvJs>w0h2R385!%w)PxhWr&M01bMie zx>a1ez2u_4;Q$qR#^a%(z`bD;W}PcbW;gZp$;XJ(jj16;20aY3xp5(V_)^EWM`}Gr zK#ADYB0DVWY&9JP_oH)FDL~K(Y0HNT%jo5+7MAC6`q*B*BqP)IfOA zSs1}p4ht#5?g87B?XYTl`HxLvWh($kg4e|Fz2Zvohr;hXR?n)(=s&V%ugp%$J_YTVFooJk<#&j9b704}aM+b!QM* zY2B{6NUDF@2GpzM?B-{6Ghg#rk|qw*Qr=FO%CA^HN`cxwni?*?^I8;o%^2I|#b!@H z!~kFZVrVLm*xR}zG$0!nJB)j{!+gufR3EieNl0$mvb9e%%PXc-huMH^XTw*p?1 zYyBDhW(uaF%N2hMyCTWakzvUi@hY_+R8p{u`b*vcrP^U z_*g|+yWK|d2olI`sQ^ThBwo*25*7;P@yH3tB(f9HU$-isz0RnuWHIEzUyNIb?n@Re zv$Du(b|ul3b3Fq0U>?6%DxBrqHZ@M!(Q9Sr<$XXSD&RZR=lmi8#WaVOpR03FJ!gJX7}xq)vi!L65L~h`COI7w7PQN!xMG^TmKZsOTAK%u z#7EYSymBa>Y&`4@Ffm&lxog|JGhG>BPx$u;Ig zhanra)@5TBV{@8(le)od=MZScTHK2=8cikHIuNW>^0PQLiQ-@U95r?P0sc?spnX8XB-Fwp8ZN9nk*gQNY==j2)0kCP> zDS3wH9LV%ani_3bU2|xy#zAU$rwL<`uAe~6y>{(&G8kQVUiZh>m`rur~bZ0XVL~QQ(q<_ClM)5o8+`+95hA?X0lOj&2f6?i%}xEm~y3R zZA1w3h^*;MJ*GFdRrP9o(a}EeSy$0MRB1H>ND#EI?o(ILX|D1yXsML7Jz;PiQelZ+ zp!i9t0BZQ}Y0c!zH|4A21GdDR7i)Cpg{XY}^=@lm1vWb9>y^p4F^Fj{5|XH~U(`1y zf0U&kUb4c0uQ(#`!MNRwE;%*DP}`saRhM}Q@8)WSInEKkDq_N)ih@A^4cDIuzpTR1 zg1^TRqQx;vVRq~}7XnA(a3&`_p-X}Rp+M!R82&a9yRuU2)qbcH!*(OuBG-ZxL$7^3 zk&b$I^~5I@OdQRRR`nvwa|Z8Ax*#R#RSH|9#$u7?>1oDhG*RHFDlwSr4bi&61QLwz zDLzl|vh{cbR+{+2Riced&uLkYy9`dK_ScE8u`N&ueqg2cUruA%=)P)#35CF58vwV> zIFPBlmMmvWShXzwjAC;X9Q9dnE`&F@@U8Utn=nx1ySEfLX(0((;LiiMhO*{o z332vyIVs;A+_1A?y(oW|?Fl2oUa(^_iON_+oYqiYgd}-iq2eyFl8e*2C7b|Q$7#)w zm1s2=sH^Fdv2u>d+BWU{?4KqFr-5CP>KbEH1xpYDVVij6M-c8AG=ym^@?d!I(P`9u z(W@77VDq{wy0<#R`)C@Tr;x*YPD61$^u=U&KnFrtLk+}c7XYQ}!}&%5t49-o8#I6j z8$BWc@|_PmISg)MZFq}`=(Tu&Y0*gn=!zUT%R6}HnzGC1I3zr#o#GHqMQG@>OzQj7okNAF z(psjhjkl6sE-6TI^GhnVg0K&Qnd~;28l$D{!$=pSZL9m)_hz5f__8{k;McQxsl7yL zoV4+ZL@DetHhsB+u&|Sr*#=j%+t!eitu!F$RMK>tLL_&GeKR_!oe^eQ=FnS3U9fs4 zI?FrCXlH>RT``+eW}G!(+Yec7JR&Y?WJi( zmoa%r*|6?kWI2MyMWFR&UR94W?=gsTJxJ}_*g_YkdUWL!owBrj-lX=Hx;)8+BIbFr zftcCqOWQ7{96mH7cGBrD==xgg7+$j^gyKT_a)O9QZ?{T>TX!jrkd>J#Cm|;2;tO2| z=43{SY5NJhTQKQ*&oeNy$u#WO!de&b$r+usOzH|f+vA&o_9PCcYXVad((7s>b=O!Z zxvTY)LL%1i&SDV@+C7(o`!I)3_ln}{m?q?=Y~@fKh>zj!lY5>N_O3$Ml2U5KPx+(7 zN0LYrf4JaN?NRvbXSVht{+PCc8`(XyfG??_f2D8e;jKH>`WI|T!;WbjqP9zrm*ZR7KW`bM%aMZ4>;lijsSslVlc+pT}&WfxFuQSMv0}uM1%mqJA$7GWa z6pIIode$f6LrBHlm1tMmunGE`=P4W`HIGYvT#t8kYINF0AA{{c=jGrCMA7YO`<&7m znPRW=3T+R(iyAEZD5LAgt+0a^)JQ95Y} zArV<65fxQBr;(Bl?f2HlYs0 ziGdJ%;O|#epl^W;RG_kRG@~>7OHhi=$l8MLJ1b@ZM>7{2pdviba?Qm47dPlXx4gn5 zAS((u#k2^#&-gl#^es}6f5-WyC+g41pS(8g(F7)M06uYiwe0*BfoQ)={+9!*<1+zM zpe4zFKtG#={Y zWh|VWfPQ@cp#n$BpCHi$Fq3A1NJ*f0`j5@bc=iX#zgcbujwXNJ%$8|Sv|Ql8_W^R* zf9Tq6-~sy2ga7Yw^MCDC&}KYbVj#*CIDmc}rk9j|j8g*IG1;2^%l?~tkPAUa! zoPSK-#rj{#|LUpVSk(V~Fn@15{M8crTjX;6d-DGbxPRIH@BK7?9A#=eKOijruWrUa zH|Ben#;-;|-(p?xH>CfwTj$T*@7>LQyk=br|G@pFquD<@LjKJ8-uCLNSK7B=k^Fbg zA3CS~4E^4B>8qpGw|FJ}1N48^U;fBn>u1XM)-XTrI(OM$QvTNt=KtpC^fUK+i;S=aQLge^)V~~G-zzMBoxuDS=O(|*`v;1gKX3c@GJ`*k za60qfF#ev4`Df+EpE=)Gb$=Bt{1(v`f5!Qj&icO6_{Yu)@%|;?4@$*8G>EADkeqE{m7WL`BO#91q`=2-V`_;N1uP(+}zs&l(<<*~)e?RN~b;0jj z5a;|l`5!F*{S5hjw(!SY+EDOI$ls&#chmVlGroU@`a19UEsRQj$M}a?NO>s;-~$;5 R2np~f1o-$>Q}y+){|A@R9n$~+ literal 54413 zcmafaV|Zr4wq`oEZQHiZj%|LijZQlLf{tz5M#r{o+fI6V=G-$g=gzrzeyqLskF}nv zRZs0&c;EUi2L_G~0s;*U0szbL-0C3_3~ zRZ#mYf6f1oqJoH`jHHCB8l!^by~4z}yc`4LEP@;Z?bO6{g9`Hk+s@(L1jC5Tq{1Yf z4E;CQvrx0-gF+peRxFC*gF=&$zNYjO?K|gN=WqXMz`tYs@0o%B{dRD+{C_6(f9t^g zhmNJQv6-#;f2)f2uc{u-#*U8W&i{|ewYN^n_1~cv|1J!}zc&$eaBy{T{cEpa46s*q zHFkD2cV;xTHFj}{*3kBt*FgS4A5SI|$F%$gB@It9FlC}D3y`sbZG{2P6gGwC$U`6O zb_cId9AhQl#A<&=x>-xDD%=Ppt$;y71@Lwsl{x943#T@8*?cbR<~d`@@}4V${+r$jICUIOzgZJy_9I zu*eA(F)$~J07zX%tmQN}1^wj+RM|9bbwhQA=xrPE*{vB_P!pPYT5{Or^m*;Qz#@Bl zRywCG_RDyM6bf~=xn}FtiFAw|rrUxa1+z^H`j6e|GwKDuq}P)z&@J>MEhsVBvnF|O zOEm)dADU1wi8~mX(j_8`DwMT_OUAnjbWYer;P*^Uku_qMu3}qJU zTAkza-K9aj&wcsGuhQ>RQoD?gz~L8RwCHOZDzhBD$az*$TQ3!uygnx_rsXG`#_x5t zn*lb(%JI3%G^MpYp-Y(KI4@_!&kBRa3q z|Fzn&3R%ZsoMNEn4pN3-BSw2S_{IB8RzRv(eQ1X zyBQZHJ<(~PfUZ~EoI!Aj`9k<+Cy z2DtI<+9sXQu!6&-Sk4SW3oz}?Q~mFvy(urUy<)x!KQ>#7yIPC)(ORhKl7k)4eSy~} z7#H3KG<|lt68$tk^`=yjev%^usOfpQ#+Tqyx|b#dVA(>fPlGuS@9ydo z!Cs#hse9nUETfGX-7lg;F>9)+ml@M8OO^q|W~NiysX2N|2dH>qj%NM`=*d3GvES_# zyLEHw&1Fx<-dYxCQbk_wk^CI?W44%Q9!!9aJKZW-bGVhK?N;q`+Cgc*WqyXcxZ%U5QXKu!Xn)u_dxeQ z;uw9Vysk!3OFzUmVoe)qt3ifPin0h25TU zrG*03L~0|aaBg7^YPEW^Yq3>mSNQgk-o^CEH?wXZ^QiPiuH}jGk;75PUMNquJjm$3 zLcXN*uDRf$Jukqg3;046b;3s8zkxa_6yAlG{+7{81O3w96i_A$KcJhD&+oz1<>?lun#C3+X0q zO4JxN{qZ!e#FCl@e_3G?0I^$CX6e$cy7$BL#4<`AA)Lw+k`^15pmb-447~5lkSMZ` z>Ce|adKhb-F%yy!vx>yQbXFgHyl(an=x^zi(!-~|k;G1=E(e@JgqbAF{;nv`3i)oi zDeT*Q+Mp{+NkURoabYb9@#Bi5FMQnBFEU?H{~9c;g3K%m{+^hNe}(MdpPb?j9`?2l z#%AO!|2QxGq7-2Jn2|%atvGb(+?j&lmP509i5y87`9*BSY++<%%DXb)kaqG0(4Eft zj|2!Od~2TfVTi^0dazAIeVe&b#{J4DjN6;4W;M{yWj7#+oLhJyqeRaO;>?%mX>Ec{Mp~;`bo}p;`)@5dA8fNQ38FyMf;wUPOdZS{U*8SN6xa z-kq3>*Zos!2`FMA7qjhw-`^3ci%c91Lh`;h{qX1r;x1}eW2hYaE*3lTk4GwenoxQ1kHt1Lw!*N8Z%DdZSGg5~Bw}+L!1#d$u+S=Bzo7gi zqGsBV29i)Jw(vix>De)H&PC; z-t2OX_ak#~eSJ?Xq=q9A#0oaP*dO7*MqV;dJv|aUG00UX=cIhdaet|YEIhv6AUuyM zH1h7fK9-AV)k8sr#POIhl+?Z^r?wI^GE)ZI=H!WR<|UI(3_YUaD#TYV$Fxd015^mT zpy&#-IK>ahfBlJm-J(n(A%cKV;)8&Y{P!E|AHPtRHk=XqvYUX?+9po4B$0-6t74UUef${01V{QLEE8gzw* z5nFnvJ|T4dlRiW9;Ed_yB{R@)fC=zo4hCtD?TPW*WJmMXYxN_&@YQYg zBQ$XRHa&EE;YJrS{bn7q?}Y&DH*h;){5MmE(9A6aSU|W?{3Ox%5fHLFScv7O-txuRbPG1KQtI`Oay=IcEG=+hPhlnYC;`wSHeo|XGio0aTS6&W($E$ z?N&?TK*l8;Y^-xPl-WVZwrfdiQv10KdsAb9u-*1co*0-Z(h#H)k{Vc5CT!708cs%sExvPC+7-^UY~jTfFq=cj z!Dmy<+NtKp&}}$}rD{l?%MwHdpE(cPCd;-QFPk1`E5EVNY2i6E`;^aBlx4}h*l42z zpY#2cYzC1l6EDrOY*ccb%kP;k8LHE3tP>l3iK?XZ%FI<3666yPw1rM%>eCgnv^JS_ zK7c~;g7yXt9fz@(49}Dj7VO%+P!eEm& z;z8UXs%NsQ%@2S5nve)@;yT^61BpVlc}=+i6{ZZ9r7<({yUYqe==9*Z+HguP3`sA& z{`inI4G)eLieUQ*pH9M@)u7yVnWTQva;|xq&-B<>MoP(|xP(HqeCk1&h>DHNLT>Zi zQ$uH%s6GoPAi0~)sC;`;ngsk+StYL9NFzhFEoT&Hzfma1f|tEnL0 zMWdX4(@Y*?*tM2@H<#^_l}BC&;PYJl%~E#veQ61{wG6!~nyop<^e)scV5#VkGjYc2 z$u)AW-NmMm%T7WschOnQ!Hbbw&?`oMZrJ&%dVlN3VNra1d0TKfbOz{dHfrCmJ2Jj= zS#Gr}JQcVD?S9X!u|oQ7LZ+qcq{$40 ziG5=X^+WqeqxU00YuftU7o;db=K+Tq!y^daCZgQ)O=M} zK>j*<3oxs=Rcr&W2h%w?0Cn3);~vqG>JO_tTOzuom^g&^vzlEjkx>Sv!@NNX%_C!v zaMpB>%yVb}&ND9b*O>?HxQ$5-%@xMGe4XKjWh7X>CYoRI2^JIwi&3Q5UM)?G^k8;8 zmY$u;(KjZx>vb3fe2zgD7V;T2_|1KZQW$Yq%y5Ioxmna9#xktcgVitv7Sb3SlLd6D zfmBM9Vs4rt1s0M}c_&%iP5O{Dnyp|g1(cLYz^qLqTfN6`+o}59Zlu%~oR3Q3?{Bnr zkx+wTpeag^G12fb_%SghFcl|p2~<)Av?Agumf@v7y-)ecVs`US=q~=QG%(_RTsqQi z%B&JdbOBOmoywgDW|DKR5>l$1^FPhxsBrja<&}*pfvE|5dQ7j-wV|ur%QUCRCzBR3q*X`05O3U@?#$<>@e+Zh&Z&`KfuM!0XL& zI$gc@ZpM4o>d&5)mg7+-Mmp98K^b*28(|Ew8kW}XEV7k^vnX-$onm9OtaO@NU9a|as7iA%5Wrw9*%UtJYacltplA5}gx^YQM` zVkn`TIw~avq)mIQO0F0xg)w$c)=8~6Jl|gdqnO6<5XD)&e7z7ypd3HOIR+ss0ikSVrWar?548HFQ*+hC)NPCq*;cG#B$7 z!n?{e9`&Nh-y}v=nK&PR>PFdut*q&i81Id`Z<0vXUPEbbJ|<~_D!)DJMqSF~ly$tN zygoa)um~xdYT<7%%m!K8+V(&%83{758b0}`b&=`))Tuv_)OL6pf=XOdFk&Mfx9y{! z6nL>V?t=#eFfM$GgGT8DgbGRCF@0ZcWaNs_#yl+6&sK~(JFwJmN-aHX{#Xkpmg;!} zgNyYYrtZdLzW1tN#QZAh!z5>h|At3m+ryJ-DFl%V>w?cmVTxt^DsCi1ZwPaCe*D{) z?#AZV6Debz{*D#C2>44Czy^yT3y92AYDcIXtZrK{L-XacVl$4i=X2|K=Fy5vAzhk{ zu3qG=qSb_YYh^HirWf~n!_Hn;TwV8FU9H8+=BO)XVFV`nt)b>5yACVr!b98QlLOBDY=^KS<*m9@_h3;64VhBQzb_QI)gbM zSDto2i*iFrvxSmAIrePB3i`Ib>LdM8wXq8(R{-)P6DjUi{2;?}9S7l7bND4w%L2!; zUh~sJ(?Yp}o!q6)2CwG*mgUUWlZ;xJZo`U`tiqa)H4j>QVC_dE7ha0)nP5mWGB268 zn~MVG<#fP#R%F=Ic@(&Va4dMk$ysM$^Avr1&hS!p=-7F>UMzd(M^N9Ijb|364}qcj zcIIh7suk$fQE3?Z^W4XKIPh~|+3(@{8*dSo&+Kr(J4^VtC{z*_{2}ld<`+mDE2)S| zQ}G#Q0@ffZCw!%ZGc@kNoMIdQ?1db%N1O0{IPPesUHI;(h8I}ETudk5ESK#boZgln z(0kvE`&6z1xH!s&={%wQe;{^&5e@N0s7IqR?L*x%iXM_czI5R1aU?!bA7)#c4UN2u zc_LZU+@elD5iZ=4*X&8%7~mA;SA$SJ-8q^tL6y)d150iM)!-ry@TI<=cnS#$kJAS# zq%eK**T*Wi2OlJ#w+d_}4=VN^A%1O+{?`BK00wkm)g8;u?vM;RR+F1G?}({ENT3i= zQsjJkp-dmJ&3-jMNo)wrz0!g*1z!V7D(StmL(A}gr^H-CZ~G9u?*Uhcx|x7rb`v^X z9~QGx;wdF4VcxCmEBp$F#sms@MR?CF67)rlpMxvwhEZLgp2?wQq|ci#rLtrYRV~iR zN?UrkDDTu114&d~Utjcyh#tXE_1x%!dY?G>qb81pWWH)Ku@Kxbnq0=zL#x@sCB(gs zm}COI(!{6-XO5li0>1n}Wz?w7AT-Sp+=NQ1aV@fM$`PGZjs*L+H^EW&s!XafStI!S zzgdntht=*p#R*o8-ZiSb5zf6z?TZr$^BtmIfGAGK;cdg=EyEG)fc*E<*T=#a?l=R5 zv#J;6C(umoSfc)W*EODW4z6czg3tXIm?x8{+8i^b;$|w~k)KLhJQnNW7kWXcR^sol z1GYOp?)a+}9Dg*nJ4fy*_riThdkbHO37^csfZRGN;CvQOtRacu6uoh^gg%_oEZKDd z?X_k67s$`|Q&huidfEonytrq!wOg07H&z@`&BU6D114p!rtT2|iukF}>k?71-3Hk< zs6yvmsMRO%KBQ44X4_FEYW~$yx@Y9tKrQ|rC1%W$6w}-9!2%4Zk%NycTzCB=nb)r6*92_Dg+c0;a%l1 zsJ$X)iyYR2iSh|%pIzYV1OUWER&np{w1+RXb~ zMUMRymjAw*{M)UtbT)T!kq5ZAn%n=gq3ssk3mYViE^$paZ;c^7{vXDJ`)q<}QKd2?{r9`X3mpZ{AW^UaRe2^wWxIZ$tuyKzp#!X-hXkHwfD zj@2tA--vFi3o_6B?|I%uwD~emwn0a z+?2Lc1xs(`H{Xu>IHXpz=@-84uw%dNV;{|c&ub|nFz(=W-t4|MME(dE4tZQi?0CE|4_?O_dyZj1)r zBcqB8I^Lt*#)ABdw#yq{OtNgf240Jvjm8^zdSf40 z;H)cp*rj>WhGSy|RC5A@mwnmQ`y4{O*SJ&S@UFbvLWyPdh)QnM=(+m3p;0&$^ysbZ zJt!ZkNQ%3hOY*sF2_~-*`aP|3Jq7_<18PX*MEUH*)t{eIx%#ibC|d&^L5FwoBN}Oe z?!)9RS@Zz%X1mqpHgym75{_BM4g)k1!L{$r4(2kL<#Oh$Ei7koqoccI3(MN1+6cDJ zp=xQhmilz1?+ZjkX%kfn4{_6K_D{wb~rdbkh!!k!Z@cE z^&jz55*QtsuNSlGPrU=R?}{*_8?4L7(+?>?(^3Ss)f!ou&{6<9QgH>#2$?-HfmDPN z6oIJ$lRbDZb)h-fFEm^1-v?Slb8udG{7GhbaGD_JJ8a9f{6{TqQN;m@$&)t81k77A z?{{)61za|e2GEq2)-OqcEjP`fhIlUs_Es-dfgX-3{S08g`w=wGj2{?`k^GD8d$}6Z zBT0T1lNw~fuwjO5BurKM593NGYGWAK%UCYiq{$p^GoYz^Uq0$YQ$j5CBXyog8(p_E znTC+$D`*^PFNc3Ih3b!2Lu|OOH6@46D)bbvaZHy%-9=$cz}V^|VPBpmPB6Ivzlu&c zPq6s7(2c4=1M;xlr}bkSmo9P`DAF>?Y*K%VPsY`cVZ{mN&0I=jagJ?GA!I;R)i&@{ z0Gl^%TLf_N`)`WKs?zlWolWvEM_?{vVyo(!taG$`FH2bqB`(o50pA=W34kl-qI62lt z1~4LG_j%sR2tBFteI{&mOTRVU7AH>>-4ZCD_p6;-J<=qrod`YFBwJz(Siu(`S}&}1 z6&OVJS@(O!=HKr-Xyzuhi;swJYK*ums~y1ePdX#~*04=b9)UqHHg;*XJOxnS6XK#j zG|O$>^2eW2ZVczP8#$C`EpcWwPFX4^}$omn{;P(fL z>J~%-r5}*D3$Kii z34r@JmMW2XEa~UV{bYP=F;Y5=9miJ+Jw6tjkR+cUD5+5TuKI`mSnEaYE2=usXNBs9 zac}V13%|q&Yg6**?H9D620qj62dM+&&1&a{NjF}JqmIP1I1RGppZ|oIfR}l1>itC% zl>ed${{_}8^}m2^br*AIX$L!Vc?Sm@H^=|LnpJg`a7EC+B;)j#9#tx-o0_e4!F5-4 zF4gA;#>*qrpow9W%tBzQ89U6hZ9g=-$gQpCh6Nv_I0X7t=th2ajJ8dBbh{i)Ok4{I z`Gacpl?N$LjC$tp&}7Sm(?A;;Nb0>rAWPN~@3sZ~0_j5bR+dz;Qs|R|k%LdreS3Nn zp*36^t#&ASm=jT)PIjNqaSe4mTjAzlAFr*@nQ~F+Xdh$VjHWZMKaI+s#FF#zjx)BJ zufxkW_JQcPcHa9PviuAu$lhwPR{R{7CzMUi49=MaOA%ElpK;A)6Sgsl7lw)D$8FwE zi(O6g;m*86kcJQ{KIT-Rv&cbv_SY4 zpm1|lSL*o_1LGOlBK0KuU2?vWcEcQ6f4;&K=&?|f`~X+s8H)se?|~2HcJo{M?Ity) zE9U!EKGz2^NgB6Ud;?GcV*1xC^1RYIp&0fr;DrqWLi_Kts()-#&3|wz{wFQsKfnnsC||T?oIgUp z{O(?Df7&vW!i#_~*@naguLLjDAz+)~*_xV2iz2?(N|0y8DMneikrT*dG`mu6vdK`% z=&nX5{F-V!Reau}+w_V3)4?}h@A@O)6GCY7eXC{p-5~p8x{cH=hNR;Sb{*XloSZ_%0ZKYG=w<|!vy?spR4!6mF!sXMUB5S9o_lh^g0!=2m55hGR; z-&*BZ*&;YSo474=SAM!WzrvjmNtq17L`kxbrZ8RN419e=5CiQ-bP1j-C#@@-&5*(8 zRQdU~+e(teUf}I3tu%PB1@Tr{r=?@0KOi3+Dy8}+y#bvgeY(FdN!!`Kb>-nM;7u=6 z;0yBwOJ6OdWn0gnuM{0`*fd=C(f8ASnH5aNYJjpbY1apTAY$-%)uDi$%2)lpH=#)=HH z<9JaYwPKil@QbfGOWvJ?cN6RPBr`f+jBC|-dO|W@x_Vv~)bmY(U(!cs6cnhe0z31O z>yTtL4@KJ*ac85u9|=LFST22~!lb>n7IeHs)_(P_gU}|8G>{D_fJX)8BJ;Se? z67QTTlTzZykb^4!{xF!=C}VeFd@n!9E)JAK4|vWVwWop5vSWcD<;2!88v-lS&ve7C zuYRH^85#hGKX(Mrk};f$j_V&`Nb}MZy1mmfz(e`nnI4Vpq(R}26pZx?fq%^|(n~>* z5a5OFtFJJfrZmgjyHbj1`9||Yp?~`p2?4NCwu_!!*4w8K`&G7U_|np&g7oY*-i;sI zu)~kYH;FddS{7Ri#Z5)U&X3h1$Mj{{yk1Q6bh4!7!)r&rqO6K~{afz@bis?*a56i& zxi#(Ss6tkU5hDQJ0{4sKfM*ah0f$>WvuRL zunQ-eOqa3&(rv4kiQ(N4`FO6w+nko_HggKFWx@5aYr}<~8wuEbD(Icvyl~9QL^MBt zSvD)*C#{2}!Z55k1ukV$kcJLtW2d~%z$t0qMe(%2qG`iF9K_Gsae7OO%Tf8E>ooch ztAw01`WVv6?*14e1w%Wovtj7jz_)4bGAqqo zvTD|B4)Ls8x7-yr6%tYp)A7|A)x{WcI&|&DTQR&2ir(KGR7~_RhNOft)wS<+vQ*|sf;d>s zEfl&B^*ZJp$|N`w**cXOza8(ARhJT{O3np#OlfxP9Nnle4Sto)Fv{w6ifKIN^f1qO*m8+MOgA1^Du!=(@MAh8)@wU8t=Ymh!iuT_lzfm za~xEazL-0xwy9$48!+?^lBwMV{!Gx)N>}CDi?Jwax^YX@_bxl*+4itP;DrTswv~n{ zZ0P>@EB({J9ZJ(^|ptn4ks^Z2UI&87d~J_^z0&vD2yb%*H^AE!w= zm&FiH*c%vvm{v&i3S>_hacFH${|(2+q!`X~zn4$aJDAry>=n|{C7le(0a)nyV{kAD zlud4-6X>1@-XZd`3SKKHm*XNn_zCyKHmf*`C_O509$iy$Wj`Sm3y?nWLCDy>MUx1x zl-sz7^{m(&NUk*%_0(G^>wLDnXW90FzNi$Tu6* z<+{ePBD`%IByu977rI^x;gO5M)Tfa-l*A2mU-#IL2?+NXK-?np<&2rlF;5kaGGrx2 zy8Xrz`kHtTVlSSlC=nlV4_oCsbwyVHG4@Adb6RWzd|Otr!LU=% zEjM5sZ#Ib4#jF(l!)8Na%$5VK#tzS>=05GpV?&o* z3goH1co0YR=)98rPJ~PuHvkA59KUi#i(Mq_$rApn1o&n1mUuZfFLjx@3;h`0^|S##QiTP8rD`r8P+#D@gvDJh>amMIl065I)PxT6Hg(lJ?X7*|XF2Le zv36p8dWHCo)f#C&(|@i1RAag->5ch8TY!LJ3(+KBmLxyMA%8*X%_ARR*!$AL66nF= z=D}uH)D)dKGZ5AG)8N-;Il*-QJ&d8u30&$_Q0n1B58S0ykyDAyGa+BZ>FkiOHm1*& zNOVH;#>Hg5p?3f(7#q*dL74;$4!t?a#6cfy#}9H3IFGiCmevir5@zXQj6~)@zYrWZ zRl*e66rjwksx-)Flr|Kzd#Bg>We+a&E{h7bKSae9P~ z(g|zuXmZ zD?R*MlmoZ##+0c|cJ(O{*h(JtRdA#lChYhfsx25(Z`@AK?Q-S8_PQqk z>|Z@Ki1=wL1_c6giS%E4YVYD|Y-{^ZzFwB*yN8-4#+TxeQ`jhks7|SBu7X|g=!_XL z`mY=0^chZfXm%2DYHJ4z#soO7=NONxn^K3WX={dV>$CTWSZe@<81-8DVtJEw#Uhd3 zxZx+($6%4a&y_rD8a&E`4$pD6-_zZJ%LEE*1|!9uOm!kYXW< zOBXZAowsX-&$5C`xgWkC43GcnY)UQt2Qkib4!!8Mh-Q!_M%5{EC=Gim@_;0+lP%O^ zG~Q$QmatQk{Mu&l{q~#kOD;T-{b1P5u7)o-QPPnqi?7~5?7%IIFKdj{;3~Hu#iS|j z)Zoo2wjf%+rRj?vzWz(6JU`=7H}WxLF*|?WE)ci7aK?SCmd}pMW<{#1Z!_7BmVP{w zSrG>?t}yNyCR%ZFP?;}e8_ zRy67~&u11TN4UlopWGj6IokS{vB!v!n~TJYD6k?~XQkpiPMUGLG2j;lh>Eb5bLTkX zx>CZlXdoJsiPx=E48a4Fkla>8dZYB%^;Xkd(BZK$z3J&@({A`aspC6$qnK`BWL;*O z-nRF{XRS`3Y&b+}G&|pE1K-Ll_NpT!%4@7~l=-TtYRW0JJ!s2C-_UsRBQ=v@VQ+4> z*6jF0;R@5XLHO^&PFyaMDvyo?-lAD(@H61l-No#t@at@Le9xOgTFqkc%07KL^&iss z!S2Ghm)u#26D(e1Q7E;L`rxOy-N{kJ zTgfw}az9=9Su?NEMMtpRlYwDxUAUr8F+P=+9pkX4%iA4&&D<|=B|~s*-U+q6cq`y* zIE+;2rD7&D5X;VAv=5rC5&nP$E9Z3HKTqIFCEV%V;b)Y|dY?8ySn|FD?s3IO>VZ&&f)idp_7AGnwVd1Z znBUOBA}~wogNpEWTt^1Rm-(YLftB=SU|#o&pT7vTr`bQo;=ZqJHIj2MP{JuXQPV7% z0k$5Ha6##aGly<}u>d&d{Hkpu?ZQeL_*M%A8IaXq2SQl35yW9zs4^CZheVgHF`%r= zs(Z|N!gU5gj-B^5{*sF>;~fauKVTq-Ml2>t>E0xl9wywD&nVYZfs1F9Lq}(clpNLz z4O(gm_i}!k`wUoKr|H#j#@XOXQ<#eDGJ=eRJjhOUtiKOG;hym-1Hu)1JYj+Kl*To<8( za1Kf4_Y@Cy>eoC59HZ4o&xY@!G(2p^=wTCV>?rQE`Upo^pbhWdM$WP4HFdDy$HiZ~ zRUJFWTII{J$GLVWR?miDjowFk<1#foE3}C2AKTNFku+BhLUuT>?PATB?WVLzEYyu+ zM*x((pGdotzLJ{}R=OD*jUexKi`mb1MaN0Hr(Wk8-Uj0zA;^1w2rmxLI$qq68D>^$ zj@)~T1l@K|~@YJ6+@1vlWl zHg5g%F{@fW5K!u>4LX8W;ua(t6YCCO_oNu}IIvI6>Fo@MilYuwUR?9p)rKNzDmTAN zzN2d>=Za&?Z!rJFV*;mJ&-sBV80%<-HN1;ciLb*Jk^p?u<~T25%7jjFnorfr={+wm zzl5Q6O>tsN8q*?>uSU6#xG}FpAVEQ_++@}G$?;S7owlK~@trhc#C)TeIYj^N(R&a} zypm~c=fIs;M!YQrL}5{xl=tUU-Tfc0ZfhQuA-u5(*w5RXg!2kChQRd$Fa8xQ0CQIU zC`cZ*!!|O!*y1k1J^m8IIi|Sl3R}gm@CC&;4840^9_bb9%&IZTRk#=^H0w%`5pMDCUef5 zYt-KpWp2ijh+FM`!zZ35>+7eLN;s3*P!bp%-oSx34fdTZ14Tsf2v7ZrP+mitUx$rS zW(sOi^CFxe$g3$x45snQwPV5wpf}>5OB?}&Gh<~i(mU&ss#7;utaLZ!|KaTHniGO9 zVC9OTzuMKz)afey_{93x5S*Hfp$+r*W>O^$2ng|ik!<`U1pkxm3*)PH*d#>7md1y} zs7u^a8zW8bvl92iN;*hfOc-=P7{lJeJ|3=NfX{(XRXr;*W3j845SKG&%N zuBqCtDWj*>KooINK1 zFPCsCWr!-8G}G)X*QM~34R*k zmRmDGF*QE?jCeNfc?k{w<}@29e}W|qKJ1K|AX!htt2|B`nL=HkC4?1bEaHtGBg}V( zl(A`6z*tck_F$4;kz-TNF%7?=20iqQo&ohf@S{_!TTXnVh}FaW2jxAh(DI0f*SDG- z7tqf5X@p#l?7pUNI(BGi>n_phw=lDm>2OgHx-{`T>KP2YH9Gm5ma zb{>7>`tZ>0d5K$j|s2!{^sFWQo3+xDb~#=9-jp(1ydI3_&RXGB~rxWSMgDCGQG)oNoc#>)td zqE|X->35U?_M6{^lB4l(HSN|`TC2U*-`1jSQeiXPtvVXdN-?i1?d#;pw%RfQuKJ|e zjg75M+Q4F0p@8I3ECpBhGs^kK;^0;7O@MV=sX^EJLVJf>L;GmO z3}EbTcoom7QbI(N8ad!z(!6$!MzKaajSRb0c+ZDQ($kFT&&?GvXmu7+V3^_(VJx1z zP-1kW_AB&_A;cxm*g`$ z#Pl@Cg{siF0ST2-w)zJkzi@X)5i@)Z;7M5ewX+xcY36IaE0#flASPY2WmF8St0am{ zV|P|j9wqcMi%r-TaU>(l*=HxnrN?&qAyzimA@wtf;#^%{$G7i4nXu=Pp2#r@O~wi)zB>@25A*|axl zEclXBlXx1LP3x0yrSx@s-kVW4qlF+idF+{M7RG54CgA&soDU-3SfHW@-6_ z+*;{n_SixmGCeZjHmEE!IF}!#aswth_{zm5Qhj0z-@I}pR?cu=P)HJUBClC;U+9;$#@xia30o$% zDw%BgOl>%vRenxL#|M$s^9X}diJ9q7wI1-0n2#6>@q}rK@ng(4M68(t52H_Jc{f&M9NPxRr->vj-88hoI?pvpn}llcv_r0`;uN>wuE{ z&TOx_i4==o;)>V4vCqG)A!mW>dI^Ql8BmhOy$6^>OaUAnI3>mN!Zr#qo4A>BegYj` zNG_)2Nvy2Cqxs1SF9A5HHhL7sai#Umw%K@+riaF+q)7&MUJvA&;$`(w)+B@c6!kX@ zzuY;LGu6|Q2eu^06PzSLspV2v4E?IPf`?Su_g8CX!75l)PCvyWKi4YRoRThB!-BhG zubQ#<7oCvj@z`^y&mPhSlbMf0<;0D z?5&!I?nV-jh-j1g~&R(YL@c=KB_gNup$8abPzXZN`N|WLqxlN)ZJ+#k4UWq#WqvVD z^|j+8f5uxTJtgcUscKTqKcr?5g-Ih3nmbvWvvEk})u-O}h$=-p4WE^qq7Z|rLas0$ zh0j&lhm@Rk(6ZF0_6^>Rd?Ni-#u1y`;$9tS;~!ph8T7fLlYE{P=XtWfV0Ql z#z{_;A%p|8+LhbZT0D_1!b}}MBx9`R9uM|+*`4l3^O(>Mk%@ha>VDY=nZMMb2TnJ= zGlQ+#+pmE98zuFxwAQcVkH1M887y;Bz&EJ7chIQQe!pgWX>(2ruI(emhz@_6t@k8Z zqFEyJFX2PO`$gJ6p$=ku{7!vR#u+$qo|1r;orjtp9FP^o2`2_vV;W&OT)acRXLN^m zY8a;geAxg!nbVu|uS8>@Gvf@JoL&GP`2v4s$Y^5vE32&l;2)`S%e#AnFI-YY7_>d#IKJI!oL6e z_7W3e=-0iz{bmuB*HP+D{Nb;rn+RyimTFqNV9Bzpa0?l`pWmR0yQOu&9c0S*1EPr1 zdoHMYlr>BycjTm%WeVuFd|QF8I{NPT&`fm=dITj&3(M^q ze2J{_2zB;wDME%}SzVWSW6)>1QtiX)Iiy^p2eT}Ii$E9w$5m)kv(3wSCNWq=#DaKZ zs%P`#^b7F-J0DgQ1?~2M`5ClYtYN{AlU|v4pEg4z03=g6nqH`JjQuM{k`!6jaIL_F zC;sn?1x?~uMo_DFg#ypNeie{3udcm~M&bYJ1LI zE%y}P9oCX3I1Y9yhF(y9Ix_=8L(p)EYr&|XZWCOb$7f2qX|A4aJ9bl7pt40Xr zXUT#NMBB8I@xoIGSHAZkYdCj>eEd#>a;W-?v4k%CwBaR5N>e3IFLRbDQTH#m_H+4b zk2UHVymC`%IqwtHUmpS1!1p-uQB`CW1Y!+VD!N4TT}D8(V0IOL|&R&)Rwj@n8g@=`h&z9YTPDT+R9agnwPuM!JW~=_ya~% zIJ*>$Fl;y7_`B7G4*P!kcy=MnNmR`(WS5_sRsvHF42NJ;EaDram5HwQ4Aw*qbYn0j;#)bh1lyKLg#dYjN*BMlh+fxmCL~?zB;HBWho;20WA==ci0mAqMfyG>1!HW zO7rOga-I9bvut1Ke_1eFo9tbzsoPTXDW1Si4}w3fq^Z|5LGf&egnw%DV=b11$F=P~ z(aV+j8S}m=CkI*8=RcrT>GmuYifP%hCoKY22Z4 zmu}o08h3YhcXx-v-QC??8mDn<+}+*X{+gZH-I;G^|7=1fBveS?J$27H&wV5^V^P$! z84?{UeYSmZ3M!@>UFoIN?GJT@IroYr;X@H~ax*CQ>b5|Xi9FXt5j`AwUPBq`0sWEJ z3O|k+g^JKMl}L(wfCqyMdRj9yS8ncE7nI14Tv#&(?}Q7oZpti{Q{Hw&5rN-&i|=fWH`XTQSu~1jx(hqm$Ibv zRzFW9$xf@oZAxL~wpj<0ZJ3rdPAE=0B>G+495QJ7D>=A&v^zXC9)2$$EnxQJ<^WlV zYKCHb1ZzzB!mBEW2WE|QG@&k?VXarY?umPPQ|kziS4{EqlIxqYHP!HN!ncw6BKQzKjqk!M&IiOJ9M^wc~ZQ1xoaI z;4je%ern~?qi&J?eD!vTl__*kd*nFF0n6mGEwI7%dI9rzCe~8vU1=nE&n4d&8}pdL zaz`QAY?6K@{s2x%Sx%#(y+t6qLw==>2(gb>AksEebXv=@ht>NBpqw=mkJR(c?l7vo z&cV)hxNoYPGqUh9KAKT)kc(NqekzE6(wjjotP(ac?`DJF=Sb7^Xet-A3PRl%n&zKk zruT9cS~vV1{%p>OVm1-miuKr<@rotj*5gd$?K`oteNibI&K?D63RoBjw)SommJ5<4 zus$!C8aCP{JHiFn2>XpX&l&jI7E7DcTjzuLYvON2{rz<)#$HNu(;ie-5$G<%eLKnTK7QXfn(UR(n+vX%aeS6!q6kv z!3nzY76-pdJp339zsl_%EI|;ic_m56({wdc(0C5LvLULW=&tWc5PW-4;&n+hm1m`f zzQV0T>OPSTjw=Ox&UF^y< zarsYKY8}YZF+~k70=olu$b$zdLaozBE|QE@H{_R21QlD5BilYBTOyv$D5DQZ8b1r- zIpSKX!SbA0Pb5#cT)L5!KpxX+x+8DRy&`o-nj+nmgV6-Gm%Fe91R1ca3`nt*hRS|^ z<&we;TJcUuPDqkM7k0S~cR%t7a`YP#80{BI$e=E!pY}am)2v3-Iqk2qvuAa1YM>xj#bh+H2V z{b#St2<;Gg>$orQ)c2a4AwD5iPcgZ7o_}7xhO86(JSJ(q(EWKTJDl|iBjGEMbX8|P z4PQHi+n(wZ_5QrX0?X_J)e_yGcTM#E#R^u_n8pK@l5416`c9S=q-e!%0RjoPyTliO zkp{OC@Ep^#Ig-n!C)K0Cy%8~**Vci8F1U(viN{==KU0nAg2(+K+GD_Gu#Bx!{tmUm zCwTrT(tCr6X8j43_n96H9%>>?4akSGMvgd+krS4wRexwZ1JxrJy!Uhz#yt$-=aq?A z@?*)bRZxjG9OF~7d$J0cwE_^CLceRK=LvjfH-~{S><^D;6B2&p-02?cl?|$@>`Qt$ zP*iaOxg<+(rbk>34VQDQpNQ|a9*)wScu!}<{oXC87hRPqyrNWpo?#=;1%^D2n2+C* zKKQH;?rWn-@%Y9g%NHG&lHwK9pBfV1a`!TqeU_Fv8s6_(@=RHua7`VYO|!W&WL*x= zIWE9eQaPq3zMaXuf)D0$V`RIZ74f)0P73xpeyk4)-?8j;|K%pD$eq4j2%tL=;&+E91O(2p91K|85b)GQcbRe&u6Ilu@SnE={^{Ix1Eqgv8D z4=w65+&36|;5WhBm$!n*!)ACCwT9Sip#1_z&g~E1kB=AlEhO0lu`Ls@6gw*a)lzc# zKx!fFP%eSBBs)U>xIcQKF(r_$SWD3TD@^^2Ylm=kC*tR+I@X>&SoPZdJ2fT!ysjH% z-U%|SznY8Fhsq7Vau%{Ad^Pvbf3IqVk{M2oD+w>MWimJA@VSZC$QooAO3 zC=DplXdkyl>mSp^$zk7&2+eoGQ6VVh_^E#Z3>tX7Dmi<2aqlM&YBmK&U}m>a%8)LQ z8v+c}a0QtXmyd%Kc2QNGf8TK?_EK4wtRUQ*VDnf5jHa?VvH2K(FDZOjAqYufW8oIZ z31|o~MR~T;ZS!Lz%8M0*iVARJ>_G2BXEF8(}6Dmn_rFV~5NI`lJjp`Mi~g7~P%H zO`S&-)Fngo3VXDMo7ImlaZxY^s!>2|csKca6!|m7)l^M0SQT1_L~K29%x4KV8*xiu zwP=GlyIE9YPSTC0BV`6|#)30=hJ~^aYeq7d6TNfoYUkk-^k0!(3qp(7Mo-$|48d8Z2d zrsfsRM)y$5)0G`fNq!V?qQ+nh0xwFbcp{nhW%vZ?h);=LxvM(pWd9FG$Bg1;@Bv)mKDW>AP{ol zD(R~mLzdDrBv$OSi{E%OD`Ano=F^vwc)rNb*Bg3-o)bbAgYE=M7Gj2OHY{8#pM${_^ zwkU|tnTKawxUF7vqM9UfcQ`V49zg78V%W)$#5ssR}Rj7E&p(4_ib^?9luZPJ%iJTvW&-U$nFYky>KJwHpEHHx zVEC;!ETdkCnO|${Vj#CY>LLut_+c|(hpWk8HRgMGRY%E--%oKh@{KnbQ~0GZd}{b@ z`J2qHBcqqjfHk^q=uQL!>6HSSF3LXL*cCd%opM|k#=xTShX~qcxpHTW*BI!c3`)hQq{@!7^mdUaG7sFsFYnl1%blslM;?B8Q zuifKqUAmR=>33g~#>EMNfdye#rz@IHgpM$~Z7c5@bO@S>MyFE3_F}HVNLnG0TjtXU zJeRWH^j5w_qXb$IGs+E>daTa}XPtrUnnpTRO9NEx4g6uaFEfHP9gW;xZnJi{oqAH~ z5dHS(ch3^hbvkv@u3QPLuWa}ImaElDrmIc%5HN<^bwej}3+?g) z-ai7D&6Iq_P(}k`i^4l?hRLbCb>X9iq2UYMl=`9U9Rf=3Y!gnJbr?eJqy>Zpp)m>Ae zcQ4Qfs&AaE?UDTODcEj#$_n4KeERZHx-I+E5I~E#L_T3WI3cj$5EYR75H7hy%80a8Ej?Y6hv+fR6wHN%_0$-xL!eI}fdjOK7(GdFD%`f%-qY@-i@fTAS&ETI99jUVg8 zslPSl#d4zbOcrgvopvB2c2A6r^pEr&Sa5I5%@1~BpGq`Wo|x=&)WnnQjE+)$^U-wW zr2Kv?XJby(8fcn z8JgPn)2_#-OhZ+;72R6PspMfCVvtLxFHeb7d}fo(GRjm_+R(*?9QRBr+yPF(iPO~ zA4Tp1<0}#fa{v0CU6jz}q9;!3Pew>ikG1qh$5WPRTQZ~ExQH}b1hDuzRS1}65uydS z~Te*3@?o8fih=mZ`iI!hL5iv3?VUBLQv0X zLtu58MIE7Jbm?)NFUZuMN2_~eh_Sqq*56yIo!+d_zr@^c@UwR&*j!fati$W<=rGGN zD$X`$lI%8Qe+KzBU*y3O+;f-Csr4$?3_l+uJ=K@dxOfZ?3APc5_x2R=a^kLFoxt*_ z4)nvvP+(zwlT5WYi!4l7+HKqzmXKYyM9kL5wX$dTSFSN&)*-&8Q{Q$K-})rWMin8S zy*5G*tRYNqk7&+v;@+>~EIQgf_SB;VxRTQFcm5VtqtKZ)x=?-f+%OY(VLrXb^6*aP zP&0Nu@~l2L!aF8i2!N~fJiHyxRl?I1QNjB)`uP_DuaU?2W;{?0#RGKTr2qH5QqdhK zP__ojm4WV^PUgmrV)`~f>(769t3|13DrzdDeXxqN6XA|_GK*;zHU()a(20>X{y-x| z2P6Ahq;o=)Nge`l+!+xEwY`7Q(8V=93A9C+WS^W%p&yR)eiSX+lp)?*7&WSYSh4i> zJa6i5T9o;Cd5z%%?FhB?J{l+t_)c&_f86gZMU{HpOA=-KoU5lIL#*&CZ_66O5$3?# ztgjGLo`Y7bj&eYnK#5x1trB_6tpu4$EomotZLb*9l6P(JmqG`{z$?lNKgq?GAVhkA zvw!oFhLyX=$K=jTAMwDQ)E-8ZW5$X%P2$YB5aq!VAnhwGv$VR&;Ix#fu%xlG{|j_K zbEYL&bx%*YpXcaGZj<{Y{k@rsrFKh7(|saspt?OxQ~oj_6En(&!rTZPa7fLCEU~mA zB7tbVs=-;cnzv*#INgF_9f3OZhp8c5yk!Dy1+`uA7@eJfvd~g34~wKI1PW%h(y&nA zRwMni12AHEw36)C4Tr-pt6s82EJa^8N#bjy??F*rg4fS@?6^MbiY3;7x=gd~G|Hi& zwmG+pAn!aV>>nNfP7-Zn8BLbJm&7}&ZX+$|z5*5{{F}BRSxN=JKZTa#{ut$v0Z0Fs za@UjXo#3!wACv+p9k*^9^n+(0(YKIUFo`@ib@bjz?Mh8*+V$`c%`Q>mrc5bs4aEf4 zh0qtL1qNE|xQ9JrM}qE>X>Y@dQ?%` zBx(*|1FMzVY&~|dE^}gHJ37O9bjnk$d8vKipgcf+As(kt2cbxAR3^4d0?`}}hYO*O z{+L&>G>AYaauAxE8=#F&u#1YGv%`d*v+EyDcU2TnqvRE33l1r}p#Vmcl%n>NrYOqV z2Car_^^NsZ&K=a~bj%SZlfxzHAxX$>=Q|Zi;E0oyfhgGgqe1Sd5-E$8KV9=`!3jWZCb2crb;rvQ##iw}xm7Da za!H${ls5Ihwxkh^D)M<4Yy3bp<-0a+&KfV@CVd9X6Q?v)$R3*rfT@jsedSEhoV(vqv?R1E8oWV;_{l_+_6= zLjV^-bZU$D_ocfSpRxDGk*J>n4G6s-e>D8JK6-gA>aM^Hv8@)txvKMi7Pi#DS5Y?r zK0%+L;QJdrIPXS2 ztjWAxkSwt2xG$L)Zb7F??cjs!KCTF+D{mZ5e0^8bdu_NLgFHTnO*wx!_8#}NO^mu{FaYeCXGjnUgt_+B-Ru!2_Ue-0UPg2Y)K3phLmR<4 zqUCWYX!KDU!jYF6c?k;;vF@Qh^q(PWwp1ez#I+0>d7V(u_h|L+kX+MN1f5WqMLn!L z!c(pozt7tRQi&duH8n=t-|d)c^;%K~6Kpyz(o53IQ_J+aCapAif$Ek#i0F9U>i+94 zFb=OH5(fk-o`L(o|DyQ(hlozl*2cu#)Y(D*zgNMi1Z!DTex#w#)x(8A-T=S+eByJW z%-k&|XhdZOWjJ&(FTrZNWRm^pHEot_MRQ_?>tKQ&MB~g(&D_e>-)u|`Ot(4j=UT6? zQ&YMi2UnCKlBpwltP!}8a2NJ`LlfL=k8SQf69U)~=G;bq9<2GU&Q#cHwL|o4?ah1` z;fG)%t0wMC;DR?^!jCoKib_iiIjsxCSxRUgJDCE%0P;4JZhJCy)vR1%zRl>K?V6#) z2lDi*W3q9rA zo;yvMujs+)a&00~W<-MNj=dJ@4%tccwT<@+c$#CPR%#aE#Dra+-5eSDl^E>is2v^~ z8lgRwkpeU$|1LW4yFwA{PQ^A{5JY!N5PCZ=hog~|FyPPK0-i;fCl4a%1 z?&@&E-)b4cK)wjXGq|?Kqv0s7y~xqvSj-NpOImt{Riam*Z!wz-coZIMuQU>M%6ben z>P@#o^W;fizVd#?`eeEPs#Gz^ySqJn+~`Pq%-Ee6*X+E>!PJGU#rs6qu0z5{+?`-N zxf1#+JNk7e6AoJTdQwxs&GMTq?Djch_8^xL^A;9XggtGL>!@0|BRuIdE&j$tzvt7I zr@I@0<0io%lpF697s1|qNS|BsA>!>-9DVlgGgw2;;k;=7)3+&t!);W3ulPgR>#JiV zUerO;WxuJqr$ghj-veVGfKF?O7si#mzX@GVt+F&atsB@NmBoV4dK|!owGP005$7LN7AqCG(S+={YA- zn#I{UoP_$~Epc=j78{(!2NLN)3qSm-1&{F&1z4Dz&7Mj_+SdlR^Q5{J=r822d4A@?Rj~xATaWewHUOus{*C|KoH`G zHB8SUT06GpSt)}cFJ18!$Kp@r+V3tE_L^^J%9$&fcyd_AHB)WBghwqBEWW!oh@StV zDrC?ttu4#?Aun!PhC4_KF1s2#kvIh~zds!y9#PIrnk9BWkJpq}{Hlqi+xPOR&A1oP zB0~1tV$Zt1pQuHpJw1TAOS=3$Jl&n{n!a+&SgYVe%igUtvE>eHqKY0`e5lwAf}2x( zP>9Wz+9uirp7<7kK0m2&Y*mzArUx%$CkV661=AIAS=V=|xY{;$B7cS5q0)=oq0uXU z_roo90&gHSfM6@6kmB_FJZ)3y_tt0}7#PA&pWo@_qzdIMRa-;U*Dy>Oo#S_n61Fn! z%mrH%tRmvQvg%UqN_2(C#LSxgQ>m}FKLGG=uqJQuSkk=S@c~QLi4N+>lr}QcOuP&% zQCP^cRk&rk-@lpa0^Lcvdu`F*qE)-0$TnxJlwZf|dP~s8cjhL%>^+L~{umxl5Xr6@ z^7zVKiN1Xg;-h+kr4Yt2BzjZs-Mo54`pDbLc}fWq{34=6>U9@sBP~iWZE`+FhtU|x zTV}ajn*Hc}Y?3agQ+bV@oIRm=qAu%|zE;hBw7kCcDx{pm!_qCxfPX3sh5^B$k_2d` z6#rAeUZC;e-LuMZ-f?gHeZogOa*mE>ffs+waQ+fQl4YKoAyZii_!O0;h55EMzD{;) z8lSJvv((#UqgJ?SCQFqJ-UU?2(0V{;7zT3TW`u6GH6h4m3}SuAAj_K(raGBu>|S&Q zZGL?r9@caTbmRm7p=&Tv?Y1)60*9At38w)$(1c?4cpFY2RLyw9c<{OwQE{b@WI}FQ zTT<2HOF4222d%k70yL~x_d#6SNz`*%@4++8gYQ8?yq0T@w~bF@aOHL2)T4xj`AVps9k z?m;<2ClJh$B6~fOYTWIV*T9y1BpB1*C?dgE{%lVtIjw>4MK{wP6OKTb znbPWrkZjYCbr`GGa%Xo0h;iFPNJBI3fK5`wtJV?wq_G<_PZ<`eiKtvN$IKfyju*^t zXc}HNg>^PPZ16m6bfTpmaW5=qoSsj>3)HS}teRa~qj+Y}mGRE?cH!qMDBJ8 zJB!&-=MG8Tb;V4cZjI_#{>ca0VhG_P=j0kcXVX5)^Sdpk+LKNv#yhpwC$k@v^Am&! z_cz2^4Cc{_BC!K#zN!KEkPzviUFPJ^N_L-kHG6}(X#$>Q=9?!{$A(=B3)P?PkxG9gs#l! zo6TOHo$F|IvjTC3MW%XrDoc7;m-6wb9mL(^2(>PQXY53hE?%4FW$rTHtN`!VgH72U zRY)#?Y*pMA<)x3B-&fgWQ(TQ6S6nUeSY{9)XOo_k=j$<*mA=f+ghSALYwBw~!Egn!jtjubOh?6Cb-Zi3IYn*fYl()^3u zRiX0I{5QaNPJ9w{yh4(o#$geO7b5lSh<5ZaRg9_=aFdZjxjXv(_SCv^v-{ZKQFtAA}kw=GPC7l81GY zeP@0Da{aR#{6`lbI0ON0y#K=t|L*}MG_HSl$e{U;v=BSs{SU3(e*qa(l%rD;(zM^3 zrRgN3M#Sf(Cr9>v{FtB`8JBK?_zO+~{H_0$lLA!l{YOs9KQd4Zt<3*Ns7dVbT{1Ut z?N9{XkN(96?r(4BH~3qeiJ_CAt+h1}O_4IUF$S(5EyTyo=`{^16P z=VhDY!NxkDukQz>T`0*H=(D3G7Np*2P`s(6M*(*ZJa;?@JYj&_z`d5bap=KK37p3I zr5#`%aC)7fUo#;*X5k7g&gQjxlC9CF{0dz*m2&+mf$Sc1LnyXn9lpZ!!Bl!@hnsE5px};b-b-`qne0Kh;hziNC zXV|zH%+PE!2@-IrIq!HM2+ld;VyNUZiDc@Tjt|-1&kq}>muY;TA3#Oy zWdYGP3NOZWSWtx6?S6ES@>)_Yz%%nLG3P>Z7`SrhkZ?shTfrHkYI;2zAn8h65wV3r z^{4izW-c9!MTge3eN=~r5aTnz6*6l#sD68kJ7Nv2wMbL~Ojj0H;M`mAvk*`Q!`KI? z7nCYBqbu$@MSNd+O&_oWdX()8Eh|Z&v&dJPg*o-sOBb2hriny)< zd(o&&kZM^NDtV=hufp8L zCkKu7)k`+czHaAU567$?GPRGdkb4$37zlIuS&<&1pgArURzoWCbyTEl9OiXZBn4p<$48-Gekh7>e)v*?{9xBt z=|Rx!@Y3N@ffW5*5!bio$jhJ7&{!B&SkAaN`w+&3x|D^o@s{ZAuqNss8K;211tUWIi1B!%-ViYX+Ys6w)Q z^o1{V=hK#+tt&aC(g+^bt-J9zNRdv>ZYm9KV^L0y-yoY7QVZJ_ivBS02I|mGD2;9c zR%+KD&jdXjPiUv#t1VmFOM&=OUE2`SNm4jm&a<;ZH`cYqBZoAglCyixC?+I+}*ScG#;?SEAFob{v0ZKw{`zw*tX}<2k zoH(fNh!>b5w8SWSV}rQ*E24cO=_eQHWy8J!5;Y>Bh|p;|nWH|nK9+ol$k`A*u*Y^Uz^%|h4Owu}Cb$zhIxlVJ8XJ0xtrErT zcK;34CB;ohd|^NfmVIF=XlmB5raI}nXjFz;ObQ4Mpl_`$dUe7sj!P3_WIC~I`_Xy@ z>P5*QE{RSPpuV=3z4p3}dh>Dp0=We@fdaF{sJ|+_E*#jyaTrj-6Y!GfD@#y@DUa;& zu4Iqw5(5AamgF!2SI&WT$rvChhIB$RFFF|W6A>(L9XT{0%DM{L`knIQPC$4F`8FWb zGlem_>>JK-Fib;g*xd<-9^&_ue95grYH>5OvTiM;#uT^LVmNXM-n8chJBD2KeDV7t zbnv3CaiyN>w(HfGv86K5MEM{?f#BTR7**smpNZ}ftm+gafRSt=6fN$(&?#6m3hF!>e$X)hFyCF++Qvx(<~q3esTI zH#8Sv!WIl2<&~=B)#sz1x2=+KTHj=0v&}iAi8eD=M->H|a@Qm|CSSzH#eVIR3_Tvu zG8S**NFbz%*X?DbDuP(oNv2;Lo@#_y4k$W+r^#TtJ8NyL&&Rk;@Q}~24`BB)bgwcp z=a^r(K_NEukZ*|*7c2JKrm&h&NP)9<($f)eTN}3|Rt`$5uB0|!$Xr4Vn#i;muSljn zxG?zbRD(M6+8MzGhbOn%C`M#OcRK!&ZHihwl{F+OAnR>cyg~No44>vliu$8^T!>>*vYQJCJg=EF^lJ*3M^=nGCw`Yg@hCmP(Gq^=eCEE1!t-2>%Al{w@*c% zUK{maww*>K$tu;~I@ERb9*uU@LsIJ|&@qcb!&b zsWIvDo4#9Qbvc#IS%sV1_4>^`newSxEcE08c9?rHY2%TRJfK2}-I=Fq-C)jc`gzV( zCn?^noD(9pAf2MP$>ur0;da`>Hr>o>N@8M;X@&mkf;%2A*2CmQBXirsJLY zlX21ma}mKH_LgYUM-->;tt;6F?E5=fUWDwQhp*drQ%hH0<5t2m)rFP%=6aPIC0j$R znGI0hcV~}vk?^&G`v~YCKc7#DrdMM3TcPBmxx#XUC_JVEt@k=%3-+7<3*fTcQ>f~?TdLjv96nb66xj=wVQfpuCD(?kzs~dUV<}P+Fpd)BOTO^<*E#H zeE80(b~h<*Qgez(iFFOkl!G!6#9NZAnsxghe$L=Twi^(Q&48 zD0ohTj)kGLD){xu%pm|}f#ZaFPYpHtg!HB30>F1c=cP)RqzK2co`01O5qwAP zUJm0jS0#mci>|Nu4#MF@u-%-4t>oUTnn_#3K09Hrwnw13HO@9L;wFJ*Z@=gCgpA@p zMswqk;)PTXWuMC-^MQxyNu8_G-i3W9!MLd2>;cM+;Hf&w| zLv{p*hArp9+h2wsMqT5WVqkkc0>1uokMox{AgAvDG^YJebD-czexMB!lJKWllLoBI zetW2;;FKI1xNtA(ZWys!_un~+834+6y|uV&Lo%dKwhcoDzRADYM*peh{o`-tHvwWIBIXW`PKwS3|M>CW37Z2dr!uJWNFS5UwY4;I zNIy1^sr+@8Fob%DHRNa&G{lm?KWU7sV2x9(Ft5?QKsLXi!v6@n&Iyaz5&U*|hCz+d z9vu60IG<v6+^ZmBs_aN!}p|{f(ikVl&LcB+UY;PPz* zj84Tm>g5~-X=GF_4JrVmtEtm=3mMEL1#z+pc~t^Iify^ft~cE=R0TymXu*iQL+XLX zdSK$~5pglr3f@Lrcp`>==b5Z6r7c=p=@A5nXNacsPfr(5m;~ks@*Wu7A z%WyY$Pt*RAKHz_7cghHuQqdU>hq$vD?plol_1EU(Fkgyo&Q2&2e?FT3;H%!|bhU~D z>VX4-6}JLQz8g3%Bq}n^NhfJur~v5H0dbB^$~+7lY{f3ES}E?|JnoLsAG%l^%eu_PM zEl0W(sbMRB3rFeYG&tR~(i2J0)RjngE`N_Jvxx!UAA1mc7J>9)`c=`}4bVbm8&{A` z3sMPU-!r-8de=P(C@7-{GgB<5I%)x{WfzJwEvG#hn3ict8@mexdoTz*(XX!C&~}L* z^%3eYQ8{Smsmq(GIM4d5ilDUk{t@2@*-aevxhy7yk(wH?8yFz%gOAXRbCYzm)=AsM z?~+vo2;{-jkA%Pqwq&co;|m{=y}y2lN$QPK>G_+jP`&?U&Ubq~T`BzAj1TlC`%8+$ zzdwNf<3suPnbh&`AI7RAYuQ<#!sD|A=ky2?hca{uHsB|0VqShI1G3lG5g}9~WSvy4 zX3p~Us^f5AfXlBZ0hA;mR6aj~Q8yb^QDaS*LFQwg!!<|W!%WX9Yu}HThc7>oC9##H zEW`}UQ%JQ38UdsxEUBrA@=6R-v1P6IoIw8$8fw6F{OSC7`cOr*u?p_0*Jvj|S)1cd z-9T);F8F-Y_*+h-Yt9cQQq{E|y^b@r&6=Cd9j0EZL}Pj*RdyxgJentY49AyC@PM<< zl&*aq_ubX%*pqUkQ^Zsi@DqhIeR&Ad)slJ2g zmeo&+(g!tg$z1ao1a#Qq1J022mH4}y?AvWboI4H028;trScqDQrB36t!gs|uZS9}KG0}DD$ zf2xF}M*@VJSzEJ5>ucf+L_AtN-Ht=34g&C?oPP>W^bwoigIncKUyf61!ce!2zpcNT zj&;rPGI~q2!Sy>Q7_lRX*DoIs-1Cei=Cd=+Xv4=%bn#Yqo@C=V`|QwlF0Y- zONtrwpHQ##4}VCL-1ol(e<~KU9-ja^kryz!g!})y-2S5z2^gE$Isj8l{%tF=Rzy`r z^RcP7vu`jHgHLKUE957n3j+BeE(bf;f)Zw($XaU6rZ26Upl#Yv28=8Y`hew{MbH>* z-sGI6dnb5D&dUCUBS`NLAIBP!Vi!2+~=AU+)^X^IpOEAn#+ab=`7c z%7B|mZ>wU+L;^&abXKan&N)O;=XI#dTV|9OMYxYqLbtT#GY8PP$45Rm2~of+J>>HIKIVn(uQf-rp09_MwOVIp@6!8bKV(C#(KxcW z;Pesq(wSafCc>iJNV8sg&`!g&G55<06{_1pIoL`2<7hPvAzR1+>H6Rx0Ra%4j7H-<-fnivydlm{TBr06;J-Bq8GdE^Amo)ptV>kS!Kyp*`wUx=K@{3cGZnz53`+C zLco1jxLkLNgbEdU)pRKB#Pq(#(Jt>)Yh8M?j^w&RPUueC)X(6`@@2R~PV@G(8xPwO z^B8^+`qZnQr$8AJ7<06J**+T8xIs)XCV6E_3W+al18!ycMqCfV>=rW0KBRjC* zuJkvrv;t&xBpl?OB3+Li(vQsS(-TPZ)Pw2>s8(3eF3=n*i0uqv@RM^T#Ql7(Em{(~%f2Fw|Reg@eSCey~P zBQlW)_DioA*yxxDcER@_=C1MC{UswPMLr5BQ~T6AcRyt0W44ffJG#T~Fk}wU^aYoF zYTayu-s?)<`2H(w+1(6X&I4?m3&8sok^jpXBB<|ZENso#?v@R1^DdVvKoD?}3%@{}}_E7;wt9USgrfR3(wabPRhJ{#1es81yP!o4)n~CGsh2_Yj2F^z|t zk((i&%nDLA%4KFdG96pQR26W>R2^?C1X4+a*hIzL$L=n4M7r$NOTQEo+k|2~SUI{XL{ynLSCPe%gWMMPFLO{&VN2pom zBUCQ(30qj=YtD_6H0-ZrJ46~YY*A;?tmaGvHvS^H&FXUG4)%-a1K~ly6LYaIn+4lG zt=wuGLw!%h=Pyz?TP=?6O-K-sT4W%_|Nl~;k~YA^_`gqfe{Xw=PWn#9f1mNz)sFuL zJbrevo(DPgpirvGMb6ByuEPd=Rgn}fYXqeUKyM+!n(cKeo|IY%p!#va6`D8?A*{u3 zEeWw0*oylJ1X!L#OCKktX2|>-z3#>`9xr~azOH+2dXHRwdfnpri9|xmK^Q~AuY!Fg z`9Xx?hxkJge~)NVkPQ(VaW(Ce2pXEtgY*cL8i4E)mM(iz_vdm|f@%cSb*Lw{WbShh41VGuplex9E^VvW}irx|;_{VK=N_WF39^ zH4<*peWzgc)0UQi4fBk2{FEzldDh5+KlRd!$_*@eYRMMRb1gU~9lSO_>Vh-~q|NTD zL}X*~hgMj$*Gp5AEs~>Bbjjq7G>}>ki1VxA>@kIhLe+(EQS0mjNEP&eXs5)I;7m1a zmK0Ly*!d~Dk4uxRIO%iZ!1-ztZxOG#W!Q_$M7_DKND0OwI+uC;PQCbQ#k#Y=^zQve zTZVepdX>5{JSJb;DX3%3g42Wz2D@%rhIhLBaFmx#ZV8mhya}jo1u{t^tzoiQy=jJp zjY2b7D2f$ZzJx)8fknqdD6fd5-iF8e(V}(@xe)N=fvS%{X$BRvW!N3TS8jn=P%;5j zShSbzsLs3uqycFi3=iSvqH~}bQn1WQGOL4?trj(kl?+q2R23I42!ipQ&`I*&?G#i9 zWvNh8xoGKDt>%@i0+}j?Ykw&_2C4!aYEW0^7)h2Hi7$;qgF3;Go?bs=v)kHmvd|`R z%(n94LdfxxZ)zh$ET8dH1F&J#O5&IcPH3=8o;%>OIT6w$P1Yz4S!}kJHNhMQ1(prc zM-jSA-7Iq=PiqxKSWb+YbLB-)lSkD6=!`4VL~`ExISOh2ud=TI&SKfR4J08Bad&rj zcXxMpcNgOB?w$~L7l^wPcXxw$0=$oV?)`I44)}b#ChS`_lBQhvb6ks?HDr3tFgkg&td19?b8=!sETXtp=&+3T$cCwZe z0nAET-7561gsbBws$TVjP7QxY(NuBYXVn9~9%vyN-B#&tJhWgtL1B<%BTS*-2$xB` zO)cMDHoWsm%JACZF--Pa7oP;f!n%p`*trlpvZ!HKoB={l+-(8O;;eYv2A=ra z3U7rSMCkP_6wAy`l|Se(&5|AefXvV1E#XA(LT!% zjj4|~xlZ-kPLNeQLFyXb%$K}YEfCBvHA-Znw#dZSI6V%3YD{Wj2@utT5Hieyofp6Qi+lz!u)htnI1GWzvQsA)baEuw9|+&(E@p8M+#&fsX@Kf`_YQ>VM+40YLv`3-(!Z7HKYg@+l00WGr779i-%t`kid%e zDtbh8UfBVT3|=8FrNian@aR3*DTUy&u&05x%(Lm3yNoBZXMHWS7OjdqHp>cD>g!wK z#~R{1`%v$IP;rBoP0B0P><;dxN9Xr+fp*s_EK3{EZ94{AV0#Mtv?;$1YaAdEiq5)g zYME;XN9cZs$;*2p63Q9^x&>PaA1p^5m7|W?hrXp2^m;B@xg0bD?J;wIbm6O~Nq^^K z2AYQs@7k)L#tgUkTOUHsh&*6b*EjYmwngU}qesKYPWxU-z_D> zDWr|K)XLf_3#k_9Rd;(@=P^S^?Wqlwert#9(A$*Y$s-Hy)BA0U0+Y58zs~h=YtDKxY0~BO^0&9{?6Nny;3=l59(6ec9j(79M?P1cE zex!T%$Ta-KhjFZLHjmPl_D=NhJULC}i$}9Qt?nm6K6-i8&X_P+i(c*LI3mtl3 z*B+F+7pnAZ5}UU_eImDj(et;Khf-z^4uHwrA7dwAm-e4 zwP1$Ov3NP5ts+e(SvM)u!3aZMuFQq@KE-W;K6 zag=H~vzsua&4Sb$4ja>&cSJ)jjVebuj+?ivYqrwp3!5>ul`B*4hJGrF;!`FaE+wKo z#};5)euvxC1zX0-G;AV@R(ZMl=q_~u8mQ5OYl;@BAkt)~#PynFX#c1K zUQ1^_N8g+IZwUl*n0Bb-vvliVtM=zuMGU-4a8|_8f|2GEd(2zSV?aSHUN9X^GDA8M zgTZW06m*iAy@7l>F3!7+_Y3mj^vjBsAux3$%U#d$BT^fTf-7{Y z_W0l=7$ro5IDt7jp;^cWh^Zl3Ga1qFNrprdu#g=n9=KH!CjLF#ucU5gy6*uASO~|b z7gcqm90K@rqe({P>;ww_q%4}@bq`ST8!0{V08YXY)5&V!>Td)?j7#K}HVaN4FU4DZ z%|7OppQq-h`HJ;rw-BAfH* z1H$ufM~W{%+b@9NK?RAp-$(P0N=b<(;wFbBN0{u5vc+>aoZ|3&^a866X@el7E8!E7 z=9V(Ma**m_{DKZit2k;ZOINI~E$|wO99by=HO{GNc1t?nl8soP@gxk8)WfxhIoxTP zoO`RA0VCaq)&iRDN9yh_@|zqF+f07Esbhe!e-j$^PS57%mq2p=+C%0KiwV#t^%_hH zoO?{^_yk5x~S)haR6akK6d|#2TN& zfWcN zc7QAWl)E9`!KlY>7^DNw$=yYmmRto>w0L(~fe?|n6k2TBsyG@sI)goigj=mn)E)I* z4_AGyEL7?(_+2z=1N@D}9$7FYdTu;%MFGP_mEJXc2OuXEcY1-$fpt8m_r2B|<~Xfs zX@3RQi`E-1}^9N{$(|YS@#{ZWuCxo)91{k>ESD54g_LYhm~vlOK_CAJHeYFfuIVB^%cqCfvpy#sU8Do8u}# z>>%PLKOZ^+$H54o@brtL-hHorSKcsjk_ZibBKBgyHt~L z=T6?e0oLX|h!Z3lbkPMO27MM?xn|uZAJwvmX?Yvp#lE3sQFY)xqet>`S2Y@1t)Z*& z;*I3;Ha8DFhk=YBt~{zp=%%*fEC}_8?9=(-k7HfFeN^GrhNw4e?vx*#oMztnO*&zY zmRT9dGI@O)t^=Wj&Og1R3b%(m*kb&yc;i`^-tqY9(0t!eyOkH<$@~1lXmm!SJllE_ zr~{a&w|8*LI>Z^h!m%YLgKv06Js7j7RaoX}ZJGYirR<#4Mghd{#;38j3|V+&=ZUq#1$ zgZb-7kV)WJUko?{R`hpSrC;w2{qa`(Z4gM5*ZL`|#8szO=PV^vpSI-^K_*OQji^J2 zZ_1142N}zG$1E0fI%uqHOhV+7%Tp{9$bAR=kRRs4{0a`r%o%$;vu!_Xgv;go)3!B#;hC5qD-bcUrKR&Sc%Zb1Y($r78T z=eG`X#IpBzmXm(o6NVmZdCQf6wzqawqI63v@e%3TKuF!cQ#NQbZ^?6K-3`_b=?ztW zA>^?F#dvVH=H-r3;;5%6hTN_KVZ=ps4^YtRk>P1i>uLZ)Ii2G7V5vy;OJ0}0!g>j^ z&TY&E2!|BDIf1}U(+4G5L~X6sQ_e7In0qJmWYpn!5j|2V{1zhjZt9cdKm!we6|Pp$ z07E+C8=tOwF<<}11VgVMzV8tCg+cD_z?u+$sBjwPXl^(Ge7y8-=c=fgNg@FxI1i5Y-HYQMEH z_($je;nw`Otdhd1G{Vn*w*u@j8&T=xnL;X?H6;{=WaFY+NJfB2(xN`G)LW?4u39;x z6?eSh3Wc@LR&yA2tJj;0{+h6rxF zKyHo}N}@004HA(adG~0solJ(7>?LoXKoH0~bm+xItnZ;3)VJt!?ue|~2C=ylHbPP7 zv2{DH()FXXS_ho-sbto)gk|2V#;BThoE}b1EkNYGT8U#0ItdHG>vOZx8JYN*5jUh5Fdr9#12^ zsEyffqFEQD(u&76zA^9Jklbiz#S|o1EET$ujLJAVDYF znX&4%;vPm-rT<8fDutDIPC@L=zskw49`G%}q#l$1G3atT(w70lgCyfYkg7-=+r7$%E`G?1NjiH)MvnKMWo-ivPSQHbk&_l5tedNp|3NbU^wk0SSXF9ohtM zUqXiOg*8ERKx{wO%BimK)=g^?w=pxB1Vu_x<9jKOcU7N;(!o3~UxyO+*ZCw|jy2}V*Z22~KhmvxoTszc+#EMWXTM6QF*ks% zW47#2B~?wS)6>_ciKe1Fu!@Tc6oN7e+6nriSU;qT7}f@DJiDF@P2jXUv|o|Wh1QPf zLG31d>@CpThA+Ex#y)ny8wkC4x-ELYCXGm1rFI=1C4`I5qboYgDf322B_Nk@#eMZ% znluCKW2GZ{r9HR@VY`>sNgy~s+D_GkqFyz6jgXKD)U|*eKBkJRRIz{gm3tUd*yXmR z(O4&#ZA*us6!^O*TzpKAZ#}B5@}?f=vdnqnRmG}xyt=)2o%<9jj>-4wLP1X-bI{(n zD9#|rN#J;G%LJ&$+Gl2eTRPx6BQC6Uc~YK?nMmktvy^E8#Y*6ZJVZ>Y(cgsVnd!tV z!%twMNznd)?}YCWyy1-#P|2Fu%~}hcTGoy>_uawRTVl=(xo5!%F#A38L109wyh@wm zdy+S8E_&$Gjm=7va-b7@Hv=*sNo0{i8B7=n4ex-mfg`$!n#)v@xxyQCr3m&O1Jxg! z+FXX^jtlw=utuQ+>Yj$`9!E<5-c!|FX(~q`mvt6i*K!L(MHaqZBTtuSA9V~V9Q$G? zC8wAV|#XY=;TQD#H;;dcHVb9I7Vu2nI0hHo)!_{qIa@|2}9d ztpC*Q{4Py~2;~6URN^4FBCBip`QDf|O_Y%iZyA0R`^MQf$ce0JuaV(_=YA`knEMXw zP6TbjYSGXi#B4eX=QiWqb3bEw-N*a;Yg?dsVPpeYFS*&AsqtW1j2D$h$*ZOdEb$8n0 zGET4Igs^cMTXWG{2#A7w_usx=KMmNfi4oAk8!MA8Y=Rh9^*r>jEV(-{I0=rc);`Y) zm+6KHz-;MIy|@2todN&F+Yv1e&b&ZvycbTHpDoZ>FIiUn+M-=%A2C(I*^Yx@VKf(Z zxJOny&WoWcyKodkeN^5))aV|-UBFw{?AGo?;NNFFcKzk+6|gYfA#FR=y@?;3IoQ zUMI=7lwo9gV9fRvYi}Nd)&gQw7(K3=a0#p27u6Q)7JlP#A)piUUF8B3Li&38Xk$@| z9OR+tU~qgd3T3322E))eV)hAAHYIj$TmhH#R+C-&E-}5Qd{3B}gD{MXnsrS;{Erv1 z6IyQ=S2qD>Weqqj#Pd65rDSdK54%boN+a?=CkR|agnIP6;INm0A*4gF;G4PlA^3%b zN{H%#wYu|!3fl*UL1~f+Iu|;cqDax?DBkZWSUQodSDL4Es@u6zA>sIm>^Aq-&X#X8 zI=#-ucD|iAodfOIY4AaBL$cFO@s(xJ#&_@ZbtU+jjSAW^g;_w`FK%aH_hAY=!MTjI zwh_OEJ_25zTQv$#9&u0A11x_cGd92E74AbOrD`~f6Ir9ENNQAV2_J2Ig~mHWhaO5a zc>fYG$zke^S+fBupw+klDkiljJAha z6DnTemhkf>hv`8J*W_#wBj-2w(cVtXbkWWtE(3j@!A-IfF?`r$MhVknTs3D1N`rYN zKth9jZtX#>v#%U@^DVN!;ni#n1)U&H_uB{6pcq7$TqXJX!Q0P7U*JUZyclb~)l*DS zOLpoQfW_3;a0S$#V0SOwVeeqE$Hd^L`$;l_~2giLYd?7!gUYIpOs!jqSL~pI)4`YuB_692~A z^T#YYQ_W3Rakk}$SL&{`H8mc{>j+3eKprw6BK`$vSSIn;s31M~YlJLApJ)+Gi1{^- zw96WnT9M0Vr_D=e=a}${raR{(35Q!g+8`}vOFj1e&Or(_wp2U2aVQP0_jP57 z2(R4E(E$n!xl<}Zx38wO;27wuQ`P#_j!}L2 z2qr;As4D4n2X$-Jd_-!fsbu_D(64i;c4cJnP576x_>Q4WNushFwkBV!kVd(AYFXe{ zaqO5`Qfr!#ETmE(B;u_&FITotv~W}QYFCI!&ENKIb1p4fg*Yv1)EDMb==EjHHWM#{ zGMpqb2-LXdHB@D~pE3|+B392Gh4q)y9jBd$a^&cJM60VEUnLtHQD5i-X6PVF>9m_k zDvG3P(?CzdaIrC8s4cu~N9MEb!Tt(g*GK~gIp1Gyeaw3b7#YPx_1T6i zRi#pAMr~PJKe9P~I+ARa$a!K~)t(4LaVbjva1yd;b1Yz2$7MMc`aLmMl(a^DgN(u? zq2o9&Gif@Tq~Yq+qDfx^F*nCnpuPv%hRFc$I!p74*quLt^M}D_rwl10uMTr!)(*=7 zSC5ea@#;l(h87k4T4x)(o^#l76P-GYJA(pOa&F9YT=fS<*O{4agzba^dIrh0hjls<~APlIz9{ zgRY{OMv2s|`;VCoYVj?InYoq^QWuA&*VDyOn@pPvK8l~g#1~~MGVVvtLDt}>id_Z` zn(ihfL?Y}Y4YX335m*Xx(y+bbukchHrM zycIGp#1*K3$!(tgTsMD2VyUSg^yvCwB8*V~sACE(yq2!MS6f+gsxv^GR|Q7R_euYx z&X+@@H?_oQddGxJYS&ZG-9O(X+l{wcw;W7srpYjZZvanY(>Q1utSiyuuonkjh5J0q zGz6`&meSuxixIPt{UoHVupUbFKIA+3V5(?ijn}(C(v>=v?L*lJF8|yRjl-m#^|krg zLVbFV6+VkoEGNz6he;EkP!Z6|a@n8?yCzX9>FEzLnp21JpU0x!Qee}lwVKA})LZJq zlI|C??|;gZ8#fC3`gzDU%7R87KZyd)H__0c^T^$zo@TBKTP*i{)Gp3E0TZ}s3mKSY zix@atp^j#QnSc5K&LsU38#{lUdwj%xF zcx&l^?95uq9on1m*0gp$ruu||5MQo)XaN>|ngV5Jb#^wWH^5AdYcn_1>H~XtNwJd3 zd9&?orMSSuj=lhO?6)Ay7;gdU#E}pTBa5wFu`nejq##Xd71BHzH2XqLA5 zeLEo;9$}~u0pEu@(?hXB_l;{jQ=7m?~mwj-ME~Tw-OHPrR7K2Xq9eCNwQO$hR z3_A?=`FJctNXA#yQEorVoh{RWxJbdQga zU%K##XEPgy?E|K(=o#IPgnbk7E&5%J=VHube|2%!Qp}@LznjE%VQhJ?L(XJOmFVY~ zo-az+^5!Ck7Lo<7b~XC6JFk>17*_dY;=z!<0eSdFD2L?CSp_XB+?;N+(5;@=_Ss3& zXse>@sA7hpq;IAeIp3hTe9^$DVYf&?)={zc9*hZAV)|UgKoD!1w{UVo8D)Htwi8*P z%#NAn+8sd@b{h=O)dy9EGKbpyDtl@NBZw0}+Wd=@65JyQ2QgU}q2ii;ot1OsAj zUI&+Pz+NvuRv#8ugesT<<@l4L$zso0AQMh{we$tkeG*mpLmOTiy8|dNYhsqhp+q*yfZA`Z)UC*(oxTNPfOFk3RXkbzAEPofVUy zZ3A%mO?WyTRh@WdXz+zD!ogo}gbUMV!YtTNhr zrt@3PcP%5F;_SQ>Ui`Gq-lUe&taU4*h2)6RDh@8G1$o!){k~3)DT87%tQeHYdO?B` zAmoJvG6wWS?=0(Cj?Aqj59`p(SIEvYyPGJ^reI z`Hr?3#U2zI7k0=UmqMD35l`>3xMcWlDv$oo6;b`dZq3d!~)W z=4Qk)lE8&>#HV>?kRLOHZYz83{u7?^KoXmM^pazj8`7OwQ=5I!==; zA!uN`Q#n=Drmzg}@^nG!mJp9ml3ukWk96^6*us*;&>s+7hWfLXtl?a}(|-#=P12>A zon1}yqh^?9!;on?tRd6Fk0knQSLl4vBGb87A_kJNDGyrnpmn48lz_%P{* z_G*3D#IR<2SS54L5^h*%=)4D9NPpji7DZ5&lHD|99W86QN_(|aJ<5C~PX%YB`Qt_W z>jF_Os@kI6R!ub4n-!orS(G6~mKL7()1g=Lf~{D!LR7#wRHfLxTjYr{*c{neyhz#U zbm@WBKozE+kTd+h-mgF+ELWqTKin57P;0b){ zii5=(B%S(N!Z=rAFGnM6iePtvpxB_Q9-oq_xH!URn2_d-H~i;lro8r{-g!k-Ydb6_w5K@FOV?zPF_hi z%rlxBv$lQi%bjsu^7KT~@u#*c$2-;AkuP)hVEN?W5MO8C9snj*EC&|M!aK6o12q3+ z8e?+dH17E!A$tRlbJW~GtMDkMPT=m1g-v67q{sznnWOI$`g(8E!Pf!#KpO?FETxLK z2b^8^@mE#AR1z(DT~R3!nnvq}LG2zDGoE1URR=A2SA z%lN$#V@#E&ip_KZL}Q6mvm(dsS?oHoRf8TWL~1)4^5<3JvvVbEsQqSa3(lF*_mA$g zv`LWarC79G)zR0J+#=6kB`SgjQZ2460W zN%lZt%M@=EN>Wz4I;eH>C0VnDyFe)DBS_2{h6=0ZJ*w%s)QFxLq+%L%e~UQ0mM9ud zm&|r){_<*Om%vlT(K9>dE(3AHjSYro5Y1I?ZjMqWyHzuCE0nyCn`6eq%MEt(aY=M2rIzHeMds)4^Aub^iTIT|%*izG4YH;sT`D9MR(eND-SB+e66LZT z2VX)RJsn${O{D48aUBl|(>ocol$1@glsxisc#GE*=DXHXA?|hJT#{;X{i$XibrA}X zFHJa+ssa2$F_UC(o2k2Z0vwx%Wb(<6_bdDO#=a$0gK2NoscCr;vyx?#cF)JjM%;a| z$^GIlIzvz%Hx3WVU481}_e4~aWcyC|j&BZ@uWW1`bH1y9EWXOxd~f-VE5DpueNofN zv7vZeV<*!A^|36hUE;`#x%MHhL(~?eZ5fhA9Ql3KHTWoAeO-^7&|2)$IcD1r5X#-u zN~N0$6pHPhop@t1_d`dO3#TC0>y5jm>8;$F5_A2& zt#=^IDfYv?JjPPTPNx2TL-Lrl82VClQSLWW_$3=XPbH}xM34)cyW5@lnxy=&h%eRq zv29&h^fMoxjsDnmua(>~OnX{Cq!7vM0M4Mr@_18|YuSKPBKUTV$s^So zc}JlAW&bVz|JY#Eyup6Ny{|P_s0Pq;5*tinH+>5Xa--{ z2;?2PBs((S4{g=G`S?B3Ien`o#5DmUVwzpGuABthYG~OKIY`2ms;33SN9u^I8i_H5`BQ%yOfW+N3r|ufHS_;U;TWT5z;b14n1gX%Pn`uuO z6#>Vl)L0*8yl|#mICWQUtgzeFp9$puHl~m&O+vj3Ox#SxQUa?fY*uK?A;00RiFg(G zK?g=7b5~U4QIK`C*um%=Sw=OJ1eeaV@WZ%hh-3<=lR#(Xesk%?)l4p(EpTwPvN99V@TT)!A8SeFTV+frN=r|5l?K#odjijx2nFgc3kI zC$hVs1S-!z9>xn9MZcRk0YXdYlf~8*LfH$IHKD59H&gLz%6 z#mAYSRJufbRi~LRadwM*G!O2>&U<^d`@<)otXZJJxT@G}4kTx0zPDVhVXwiU)$}5Y z`0iV`8EEh&GlUk&VY9m0Mqr*U&|^Bc?FB`<%{x-o0ATntwIA%(YDcxWs$C)%a%d_@ z?fx!Co+@3p7ha$|pWYD}p6#(PG%_h8K7sQjT_P~|3ZEH0DRxa3~bP&&lPMj3C~!H2QD zq>(f^RUFSqf6K3BMBFy$jiuoSE+DhEq$xLDb7{57 z0B|1pSjYJ5F@cHG%qDZ{ogL$P!BK&sR%zD`gbK#9gRZX17EtAJxN% zys^gb2=X9=7HP}N(iRqt(tot2yyeE%s;L}AcMh;~-W~s_eAe!gIUYdQz5j~T)0trh z>#1U$uOyyl%!Pi(gD&)uHe9Q^27_kHyFCC}n^-KL(=OxHqUfex1YS__RJh0m-S>eM zqAk`aSev*z1lI&-?CycgDm=bdQCp}RqS0_d-4Mf&>u2KyGFxKe8JM1N{GNWw0n$FL z1UDp(h0(1I2Jh9I`?IS}h4R~n zRwRz>8?$fFMB2{UPe^$Ifl;Oc>}@Q9`|8DCeR{?LUQLPfaMsxs8ps=D_aAXORZH~< zdcIOca-F;+D3~M+)Vi4h)I4O3<)$65yI)goQ_vk#fb;Uim>UI4Dv9#2b1;N_Wg>-F zNwKeMKY+su#~NL0uE%_$mw1%ddX2Qs2P!ncM+>wnz}OCQX1!q~oS?OqYU;&ESAAwP z452QWL0&u^mraF#=j_ZeBWhm&F|d!QjwRl^7=Bl7@(43=BkN=3{BRv#QHIk>Umc_w zvP>q|q{lJ=zs|W9%a@8%W>C@MYN1D5{(=Af31+pR#kB`cd0-YlQQTg}+ zL|_h=F9JQ|Gux5c0ehaffHNYLf8VwF+qnM6IjBEI_eceee;o;FY@#~FFVsZjBSp!j z8V*Bgmn{RK!!zqGc;jy)z@Zjo>5{%m1?K}fLEL$l6Dl4f=ye0wNI#)2L=^K(&18Gb zJoj8@WBB;P^T#V)I0`aDSy?$rJU{+-5472NyFp>;Vw43j@3Z=;D2eSfyw5*0Q+&ML zsV&&*3c3$pa`qcaGbEB0*CA~Wp3%PkF?B87FV&rWNb|@GU$LB;l|;YutU*k za1hjUL_BX%G^s;BuzRi4Hl?eqC2z&ZrKh1tZDwnufG$g$LX(j!h%F5(n8D@in3lnX z(*8+3ZT6TVYRcSpM1eMeCps=Fz8q%gyM&B=a7(Vf`4k3dN$IM+`BO^_7HZq4BR|7w z+5kOJ;9_$X%-~arA@qmXSzD|+NMh--%5-9u6t(M=f%&z$<_V#Y_lzn{E$MZZG)+A> zu2E`_Y(MBJ2l*AqvCUmU;yBT}#oQ{V=((mC-QGJwsCOH*a;{1JRTKv7DBNG+M!XL7(^jbv&Qy-o9HNFrmN)-`D3WFtXs>1vBOJpI(=x; zKhJlFdfMf^G#oU(w1+ucMKYPZaDp>$kt=wiYsBCjUY-uz<4JziB>6fXDSLH*2Y z&Px5y`#3!fF=c4>fCMdg-tX582pemU@ZxyFbznL8-=TTo1Sybg9>7h*J^9^~XxXJO z`k9v~=4amxl<;FCV9h2k%?^-ZUzQy^#{JleyH23o1S{r<+t#z6jKS<9rbAM96^1iY zi6{IjauB)UwBhC-_L(MzGCxhhv`?ryc zja_Uwi7$8l!}*vjJppGyp#Wz=*?;jC*xQ&J894rql5A$2giJRtV&DWQh#(+Vs3-5_ z69_tj(>8%z1VtVp>a74r5}j2rG%&;uaTQ|fr&r%ew-HO}76i8`&ki%#)~}q4Y|d$_ zfNp9uc#$#OEca>>MaY6rF`dB|5#S)bghf>>TmmE&S~IFw;PF0UztO6+R-0!TSC?QP z{b(RA_;q3QAPW^XN?qQqu{h<}Vfiv}Rr!lA$C79^1=U>+ng9Dh>v{`?AOZt>CrQ=o zI}=mSnR))8fJpO->rcX?H);oqSQUZ?sR!fH2SoFdcPm5*2y<_u;4h;BqcF*XbwWSv zcJN%!g|L(22Xp!^1?c;T&qm%rpkP&2EQC3JF+SENm$+@7#e!UKD1uQ{TDw43?!b!3 zUooS_rt=xJfa&h?c^hfV>YwQXre3qosz_^c#)FO~d!<)2o}Oxz5HWtr<)1Yw012v4 zhv0w(RfJspDnA^-6Jmr;GkWt%{mAYOm6yPb&Vl&rv@D^K&;#?=X{kaK5FhScNJ_3> z#5u(Saisq2(~pVlrfG#@kLM#Ot~5rZZc%B&h1=gen?R+#t^1bYKf zVvtefX=D$*)39e^2@!~A_}9c${Gf0?1;dk=!Itp#s%0>Io%k`9(bDeI-udd&E6Zfu zcaiv(h`DM3W3Mfda)fYwhB=8RAPkotVt5-z21Ij~Ot9A^SK-1u*zFVK&mF?q1;|wy zrF+XWs^5Q-%Z6I62gTwrRe#F>riVM#fv_TihxSJ6to1X7NVszgivoTa!fPfBBYj94 zuc2m zL_k-<1FoORng1aL{Zx(P7JmUiH zlmTHdzkn75=mS{V=o$V;gzhEaunoJzJ3uq>0_w~77eID^U*w+v0po_N8=sS-DL~!V z%-~rL<0V7PCEWPCpNgpfsein`Fr)+8=N}mUn2x=K`z%efnhSs#23&N1fjdO`M>s%z zP3(;v93%lLq>ZfqBi#QI-aCXAP8-may8x5s`G)KA;{HSYe2szWINWf^b*fc{jl0KecD zRTle?)%_YzJJcVb>;VJ>P?3Lu2S)vCJZlF>Jxj~~X2U5-NNNy(H?8%XD~yFUxNKs&hwWx^)iF@ zGmEv<|7Q7hGrY_+`iz+d_=^9c(_c}UCzq2#%A0|5WjzCXjZUOxOX zU&-^smw$iwKPe;r`&{rP{L35^&+wk6f2-Sn;D2Ww@sjAJj{Gwbp4H!o{#5_}qALFq z{-q%LGklZvKf%A4D!+t%sRRBDi(>mvuz&V4yu^GdD*KFy?fg%ef5ZU%w=d&M`POGt zNSEJ0{qJI~FRTAjlJc1-+x>Tm{%D?m3sk-&cq#w)OpxI98wCF#2KbWcrAXK_(}M4B zF#VQf*h|irx=+uXZUMi+`A;fPFR5M%Wjs^Wh5rWCKgedhWO^w|@XS;b^&3oom;>K0 zB??|ry^IBarYem6Z7RU`#rDs-ZZAn*hSollv?csD$sh0QpTtI9vb>Dpd}e7*`fZj! zM|8d{~YM@vfW-r0z8vJ z<^6B6Ur(}L?ms_c9@hO0^Iy&J_uc51^?d33e#Y!-``?)VG)BGjCq5$&0G8A*r!2qk zUHscGc;VxE=1KqbH=dW%&Ogl({>L!>((m$2W8M9KQ@a1=h51jN|KoG{v(x0K&*iy% e1c3cF4~(n?C}6GmGu)3JNC)6=LGAhZ*Z%`+-T+_# diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a95009c3..dbe66e1d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,10 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip +distributionSha256Sum=9c0f7faeeb306cb14e4279a3e084ca6b596894089a0638e68a07c945a32c9e14 +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip +networkTimeout=10000 +retries=0 +retryBackOffMs=500 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 874e1c96..249efbb0 100755 --- a/gradlew +++ b/gradlew @@ -1,78 +1,128 @@ -#!/usr/bin/env sh +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# gradlew start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh gradlew +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -81,93 +131,118 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" fi -exec "$JAVACMD" "$@" +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index e95643d6..a51ec4f5 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,84 +1,82 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem gradlew startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:execute +@rem Setup the command line + + + +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel + +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/settings.gradle b/settings.gradle index f74c120a..6505ca5e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,33 +1,5 @@ -// Workaround to make the JUnit Platform Gradle Plugin available using the `plugins` DSL -// See https://github.com/junit-team/junit5/issues/768 -if (!(GradleVersion.current() <= GradleVersion.version('2.14.1'))) { -pluginManagement { - repositories { - gradlePluginPortal() - maven { url = ArtifactRepositoryContainer.MAVEN_CENTRAL_URL } - } - resolutionStrategy { - eachPlugin { - if (requested.id.id == 'org.junit.platform.gradle.plugin') { - useModule("org.junit.platform:junit-platform-gradle-plugin:${requested.version}") -// } else if (requested.id.id == 'org.junit.platform.gradle.plugin') { -// useModule("org.junit.platform:junit-platform-gradle-plugin:${requested.version}") - } - } - } -} -} - -rootProject.name = archivesBaseName -import org.gradle.util.GradleVersion -if ((GradleVersion.current() >= GradleVersion.version('4.8')) && (GradleVersion.current() <= GradleVersion.version('4.10.3'))) { - enableFeaturePreview('STABLE_PUBLISHING') // 4.10.3 +plugins { + id('org.gradle.toolchains.foojay-resolver-convention') version '1.0.0' } -// TODO: Things which likely don't work with FG yet, but I've not checked. -/* -if ((GradleVersion.current() >= GradleVersion.version('4.6')) && (GradleVersion.current() <= GradleVersion.version('4.10.3'))) { - enableFeaturePreview('IMPROVED_POM_SUPPORT') // Previously -Dorg.gradle.advancedpomsupport=true - enableFeaturePreview('GRADLE_METADATA') // Previously -Dorg.gradle.gradlemetadata=true -} -*/ +rootProject.name = 'BaseMetals' diff --git a/src/main/java/com/mcmoddev/basemetals/BaseMetals.java b/src/main/java/com/mcmoddev/basemetals/BaseMetals.java index 4fad6ec1..35cc458b 100644 --- a/src/main/java/com/mcmoddev/basemetals/BaseMetals.java +++ b/src/main/java/com/mcmoddev/basemetals/BaseMetals.java @@ -58,7 +58,7 @@ version = BaseMetals.VERSION, dependencies = "required-after:forge@[14.23.1.2592,);required-after:mmdlib;after:tconstruct;after:conarm;after:thaumcraft;after:ic2;before:buildingbricks", acceptedMinecraftVersions = "[1.12,1.12.2]", - certificateFingerprint = "@FINGERPRINT@", + certificateFingerprint = "", updateJSON = BaseMetals.UPDATEJSON) public final class BaseMetals { @@ -82,7 +82,7 @@ public final class BaseMetals { * The Minor version number will be increased when ever there is potential for compatibility issues * with dependant mods. */ - protected static final String VERSION = "2.5.0-rc2"; + protected static final String VERSION = "2.5.1.112021"; protected static final String UPDATEJSON = SharedStrings.UPDATE_JSON_URL + "BaseMetals/master/update.json"; diff --git a/src/main/java/com/mcmoddev/orespawn/BaseMetalsOreSpawn.java b/src/main/java/com/mcmoddev/basemetals/integration/orespawn/BaseMetalsOreSpawn.java similarity index 52% rename from src/main/java/com/mcmoddev/orespawn/BaseMetalsOreSpawn.java rename to src/main/java/com/mcmoddev/basemetals/integration/orespawn/BaseMetalsOreSpawn.java index 349b3645..10635e8c 100644 --- a/src/main/java/com/mcmoddev/orespawn/BaseMetalsOreSpawn.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/orespawn/BaseMetalsOreSpawn.java @@ -1,4 +1,4 @@ -package com.mcmoddev.orespawn; +package com.mcmoddev.basemetals.integration.orespawn; import com.mcmoddev.basemetals.BaseMetals; import com.mcmoddev.lib.data.SharedStrings; @@ -6,12 +6,18 @@ import com.mcmoddev.orespawn.api.plugin.IOreSpawnPlugin; import com.mcmoddev.orespawn.api.plugin.OreSpawnPlugin; +/** + * Declares Base Metals' packaged OreSpawn 3 data. + * + *

The plugin deliberately lives outside {@code com.mcmoddev.orespawn}. + * OreSpawn 3 releases sign that package, so putting an unsigned add-on class + * in it causes the JVM's package signer check to reject the integration.

+ */ @OreSpawnPlugin(modid = BaseMetals.MODID, resourcePath = SharedStrings.ORESPAWN_MODID) public class BaseMetalsOreSpawn implements IOreSpawnPlugin { @Override public void register(final OS3API apiInterface) { - // nothing for us to do - all of our ores are in the - // jar and the code handles that + // The annotation points OreSpawn at the packaged JSON configuration. } } diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index adca71c6..0c03b9e2 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -5,7 +5,7 @@ "description": "This mod adds historically common metals to Minecraft", "version": "${version}", "mcversion": "${mcversion}", - "url": "https://github.com/MineCraftModDevelopmentMods/BaseMetals", + "url": "https://github.com/MinecraftModDevelopmentMods/BaseMetals", "updateUrl": "", "authorList": ["jriwanek", "dshadowwolf", "GetDizzy611 'Dizzy OM'"], "credits": "Cyanobacterium (aka DrCyano) For starting the project & geologists everywhere. SeqSEE for helping with shields. Vase of Petunias (aka TheUnknownFew) for creating Javadocs, YaibaToKen for Construct's Armory integration", diff --git a/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsRuntimeProbe.java b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsRuntimeProbe.java new file mode 100644 index 00000000..fe1e9eff --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsRuntimeProbe.java @@ -0,0 +1,93 @@ +package com.mcmoddev.basemetals.test; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventHandler; +import net.minecraftforge.fml.common.ModContainer; +import net.minecraftforge.fml.common.event.FMLServerStartedEvent; + +/** Test-only packaged-runtime probe. This class never enters the public jar. */ +@Mod( + modid = BaseMetalsRuntimeProbe.MODID, + name = "Base Metals Runtime Probe", + version = "1", + acceptedMinecraftVersions = "[1.12.2]") +public final class BaseMetalsRuntimeProbe { + public static final String MODID = "basemetals_runtime_probe"; + + @EventHandler + public void serverStarted(final FMLServerStartedEvent event) throws IOException { + final String expectedOreSpawn = requiredProperty("basemetals.probe.expectedOrespawn"); + final File marker = new File(requiredProperty("basemetals.probe.marker")); + final Properties result = new Properties(); + + require(Loader.isModLoaded("basemetals"), "Base Metals did not load"); + require(Loader.isModLoaded("mmdlib"), "MMDLib did not load"); + require(Loader.isModLoaded("orespawn"), "OreSpawn did not load"); + requireRegistered(Block.REGISTRY.getObject(new ResourceLocation("basemetals", "copper_ore")), + "basemetals:copper_ore"); + requireRegistered(Block.REGISTRY.getObject(new ResourceLocation("basemetals", "adamantine_ore")), + "basemetals:adamantine_ore"); + requireRegistered(Item.REGISTRY.getObject(new ResourceLocation("basemetals", "steel_ingot")), + "basemetals:steel_ingot"); + + final String baseMetalsVersion = version("basemetals"); + final String mmdLibVersion = version("mmdlib"); + final String oreSpawnVersion = version("orespawn"); + require("2.5.1.112021".equals(baseMetalsVersion), + "Unexpected Base Metals version " + baseMetalsVersion); + // The artifact build is rc2.36, while its public FML metadata retains + // the upstream mod version rc2. + require("1.0.0-rc2".equals(mmdLibVersion), + "Unexpected MMDLib version " + mmdLibVersion); + require(expectedOreSpawn.equals(oreSpawnVersion), + "Unexpected OreSpawn version " + oreSpawnVersion + ", expected " + expectedOreSpawn); + + result.setProperty("basemetals", baseMetalsVersion); + result.setProperty("mmdlib", mmdLibVersion); + result.setProperty("orespawn", oreSpawnVersion); + result.setProperty("phase", System.getProperty("basemetals.probe.phase", "unknown")); + result.setProperty("registered", "true"); + marker.getParentFile().mkdirs(); + try (FileOutputStream output = new FileOutputStream(marker)) { + result.store(output, "Base Metals packaged-runtime qualification"); + } + FMLCommonHandler.instance().getMinecraftServerInstance().initiateShutdown(); + } + + private static String requiredProperty(final String name) { + final String value = System.getProperty(name); + if (value == null || value.trim().isEmpty()) { + throw new IllegalStateException("Missing system property " + name); + } + return value; + } + + private static String version(final String modid) { + for (final ModContainer mod : Loader.instance().getModList()) { + if (modid.equals(mod.getModId())) { + return mod.getVersion(); + } + } + throw new IllegalStateException("Missing loaded mod " + modid); + } + + private static void requireRegistered(final Object value, final String registryName) { + require(value != null, "Missing registry object " + registryName); + } + + private static void require(final boolean condition, final String message) { + if (!condition) { + throw new IllegalStateException(message); + } + } +} From ab62c512fe054afd2894498f6f1ccc31bc7fad4a Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Fri, 11 Sep 2026 14:37:57 +0100 Subject: [PATCH 2/6] Fix Eclipse optional dependency isolation --- CHANGELOG.txt | 3 ++ build.gradle | 84 ++++++++++++++++++++++++++--- gradle/stage-legacy-dependencies.sh | 5 +- 3 files changed, 85 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index e92a1888..d2ccffb8 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -5,6 +5,9 @@ Base Metals 2.5.1.112021 - Added deterministic release archives, artifact auditing, Eclipse launch generation, packaged Forge runtime qualification and guarded GitHub Actions release delivery. +- Isolated ordinary Eclipse launches from compile-only integration APIs, so + optional mods such as CoFH Core are not accidentally loaded without their + dependencies. - Updated the development target to Forge 14.23.5.2859 while preserving Java 8 game compatibility, registry IDs, OreSpawn 3 behavior and integrations. - This modernization contains no gameplay or recipe-loop fixes; those changes diff --git a/build.gradle b/build.gradle index d4d8b9a4..7f451197 100644 --- a/build.gradle +++ b/build.gradle @@ -1128,6 +1128,39 @@ idea { } } +def eclipseXmlEscape = { String value -> + value.replace('&', '&') + .replace('"', '"') + .replace('<', '<') + .replace('>', '>') +} + +def eclipseArchiveLaunchEntry = { File archive -> + String memento = '' \ + + '' + ' ' +} + +def replaceBuildshipLaunchClasspath = { String contents, Collection archives -> + List lines = contents.replace('\r\n', '\n').split('\n', -1) as List + List buildshipLines = (0.. uniqueArchives = archives.collect { it.canonicalFile } + .unique { File archive -> archive.path.toLowerCase(Locale.ROOT) } + .sort { File left, File right -> left.path.compareToIgnoreCase(right.path) } + List missingArchives = uniqueArchives.findAll { !it.isFile() } + if (!missingArchives.isEmpty()) { + throw new GradleException("Eclipse launch archives are missing: ${missingArchives}") + } + lines[buildshipLines[0]] = uniqueArchives.collect(eclipseArchiveLaunchEntry).join('\n') + lines.join('\n') +} + eclipse { project { buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder' @@ -1136,6 +1169,19 @@ eclipse { classpath { downloadSources = true downloadJavadoc = true + file.withXml { provider -> + Node classpath = provider.asNode() + classpath.classpathentry.findAll { it.@kind == 'lib' }.each { + classpath.remove(it) + } + if (!classpath.classpathentry.any { + it.@kind == 'con' && it.@path == 'org.eclipse.buildship.core.gradleclasspathcontainer' + }) { + classpath.appendNode('classpathentry', [ + kind: 'con', path: 'org.eclipse.buildship.core.gradleclasspathcontainer' + ]) + } + } } synchronizationTasks 'genEclipseRuns' } @@ -1175,8 +1221,10 @@ tasks.named('eclipse') { tasks.register('isolateEclipseProductionRuns') { group = 'ide' - description = 'Repairs Forge 1.12 launches for spaces and keeps them production-only.' + description = 'Repairs Forge 1.12 launches and replaces compile-only Buildship entries with runtime jars.' + dependsOn sanitizedOrespawn3DevelopmentJar doLast { + List runtimeArchives = configurations.runtimeClasspath.files as List ['BaseMetals_Client.launch', 'BaseMetals_Server.launch'].each { name -> File legacy = file(name) if (legacy.isFile() && legacy.getText('UTF-8').contains('MAIN_TYPE" value="GradleStart')) { @@ -1227,7 +1275,8 @@ tasks.register('isolateEclipseProductionRuns') { } contents = contents.replaceAll(//, '') - launch.setText(contents, 'UTF-8') + contents = replaceBuildshipLaunchClasspath(contents, runtimeArchives) + launch.setText(contents.replace('\r\n', '\n'), 'UTF-8') } } } @@ -1254,10 +1303,18 @@ tasks.register('verifyEclipseProductionClasspath') { throw new GradleException('Eclipse project metadata is missing Buildship integration') } String eclipseClasspath = file('.classpath').getText('UTF-8').replace('\\', '/') - if (!eclipseClasspath.contains("development-dependencies/OreSpawn-${project.orespawn3_version}-development.jar") - || eclipseClasspath.contains('renamer/renamed/mmd-orespawn-')) { - throw new GradleException('Eclipse does not use the signature-free remapped OreSpawn 3 dependency') + if (!eclipseClasspath.contains('org.eclipse.buildship.core.gradleclasspathcontainer') + || eclipseClasspath.contains(']+path="[A-Za-z]:[\\\/].*/) { + throw new GradleException('Eclipse must expose dependencies through the Buildship container only') } + Set runtimeArchives = configurations.runtimeClasspath.files.collect { + it.canonicalFile + } as Set + Set compileOnlyArchives = configurations.compileClasspath.files.collect { + it.canonicalFile + } as Set + compileOnlyArchives.removeAll(runtimeArchives) ['runClient.launch', 'runServer.launch'].each { name -> File launch = file(name) String contents = launch.getText('UTF-8').replace('\\', '/') @@ -1271,10 +1328,25 @@ tasks.register('verifyEclipseProductionClasspath') { if (!contents.contains('MAIN_TYPE" value="net.minecraftforge.launcher.Main"') || !contents.contains('JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-8') || !contents.contains('ATTR_EXCLUDE_TEST_CODE') + || contents.contains('org.eclipse.buildship.core.gradleclasspathcontainer') || !contents.contains('PROJECT_ATTR" value="BaseMetals"') || contents.contains('${MC_VERSION}') || !contents.contains('MC_VERSION" value="1.12.2"')) { - throw new GradleException("${name} has the wrong launcher, JRE, project, or Minecraft version") + throw new GradleException("${name} has the wrong launcher, JRE, classpath, project, or Minecraft version") + } + Set missingRuntime = runtimeArchives.findAll { + !contents.contains(it.canonicalPath.replace('\\', '/')) + } + Set leakedCompileOnly = compileOnlyArchives.findAll { + contents.contains(it.canonicalPath.replace('\\', '/')) + } + if (!missingRuntime.isEmpty() || !leakedCompileOnly.isEmpty()) { + throw new GradleException("${name} runtime isolation failed; missing=${missingRuntime}, " + + "compileOnly=${leakedCompileOnly}") + } + if (!contents.contains("development-dependencies/OreSpawn-${project.orespawn3_version}-development.jar") + || contents.contains('renamer/renamed/mmd-orespawn-')) { + throw new GradleException("${name} does not use the signature-free remapped OreSpawn 3 dependency") } String expectedModClasses = file('bin/main').absolutePath.replace('\\', '/') if (!contents.contains('MOD_CLASSES" value="' + expectedModClasses)) { diff --git a/gradle/stage-legacy-dependencies.sh b/gradle/stage-legacy-dependencies.sh index 56afd629..940402e1 100644 --- a/gradle/stage-legacy-dependencies.sh +++ b/gradle/stage-legacy-dependencies.sh @@ -7,6 +7,9 @@ if [[ $# -ne 1 ]]; then fi destination="$1" +if command -v cygpath >/dev/null 2>&1; then + destination="$(cygpath -u "$destination")" +fi properties="gradle.properties" if [[ ! -f "$properties" ]]; then echo "Run this script from the Base Metals project root" >&2 @@ -14,7 +17,7 @@ if [[ ! -f "$properties" ]]; then fi value() { - sed -n "s/^$1=//p" "$properties" + sed -n "s/^$1=//p" "$properties" | tr -d '\r' } stage() { From 326f7de20175834cc74cb8273c8c80c9fd525ba9 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Fri, 11 Sep 2026 14:51:49 +0100 Subject: [PATCH 3/6] Preserve Forge Eclipse runtime order --- CHANGELOG.txt | 2 +- build.gradle | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index d2ccffb8..c3d0708e 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -7,7 +7,7 @@ Base Metals 2.5.1.112021 release delivery. - Isolated ordinary Eclipse launches from compile-only integration APIs, so optional mods such as CoFH Core are not accidentally loaded without their - dependencies. + dependencies, while preserving Forge's order-sensitive runtime classpath. - Updated the development target to Forge 14.23.5.2859 while preserving Java 8 game compatibility, registry IDs, OreSpawn 3 behavior and integrations. - This modernization contains no gameplay or recipe-loop fixes; those changes diff --git a/build.gradle b/build.gradle index 7f451197..c4248437 100644 --- a/build.gradle +++ b/build.gradle @@ -1152,7 +1152,6 @@ def replaceBuildshipLaunchClasspath = { String contents, Collection archiv } List uniqueArchives = archives.collect { it.canonicalFile } .unique { File archive -> archive.path.toLowerCase(Locale.ROOT) } - .sort { File left, File right -> left.path.compareToIgnoreCase(right.path) } List missingArchives = uniqueArchives.findAll { !it.isFile() } if (!missingArchives.isEmpty()) { throw new GradleException("Eclipse launch archives are missing: ${missingArchives}") @@ -1308,9 +1307,9 @@ tasks.register('verifyEclipseProductionClasspath') { || eclipseClasspath ==~ /(?s).*]+path="[A-Za-z]:[\\\/].*/) { throw new GradleException('Eclipse must expose dependencies through the Buildship container only') } - Set runtimeArchives = configurations.runtimeClasspath.files.collect { + List runtimeArchives = configurations.runtimeClasspath.files.collect { it.canonicalFile - } as Set + } Set compileOnlyArchives = configurations.compileClasspath.files.collect { it.canonicalFile } as Set @@ -1344,6 +1343,14 @@ tasks.register('verifyEclipseProductionClasspath') { throw new GradleException("${name} runtime isolation failed; missing=${missingRuntime}, " + "compileOnly=${leakedCompileOnly}") } + List runtimePositions = runtimeArchives.collect { + contents.indexOf(it.canonicalPath.replace('\\', '/')) + } + List sortedRuntimePositions = new ArrayList<>(runtimePositions) + sortedRuntimePositions.sort() + if (runtimePositions != sortedRuntimePositions) { + throw new GradleException("${name} does not preserve Gradle's order-sensitive runtime classpath") + } if (!contents.contains("development-dependencies/OreSpawn-${project.orespawn3_version}-development.jar") || contents.contains('renamer/renamed/mmd-orespawn-')) { throw new GradleException("${name} does not use the signature-free remapped OreSpawn 3 dependency") From 6aaac2adc98b814a7aa0f9aeb6b835f3f92583b6 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 29 Sep 2026 16:34:43 +0100 Subject: [PATCH 4/6] Prepare Base Metals 1.12 release candidate Fix the accepted gameplay and recipe issues, adopt OreSpawn 4.1, add content modes and configuration screens, and finish the build and source cleanup for the 2.6.0.112021 candidate. --- .editorconfig | 3 + .github/workflows/ci.yml | 6 +- README.md | 14 +- build.gradle | 1169 +---------- docs/configuration.md | 61 + .../basemetals-orespawn-disabled.json | 489 +++++ docs/world-generation.md | 56 + gradle.properties | 38 +- gradle/README.md | 33 + gradle/dependencies.gradle | 138 ++ gradle/ide/eclipse.gradle | 260 +++ gradle/release/artifacts.gradle | 236 +++ gradle/release/publishing.gradle | 77 + gradle/stage-legacy-dependencies.sh | 7 +- .../verification/packaged-forge-cofh.gradle | 113 ++ .../packaged-forge-dependencies.gradle | 206 ++ .../packaged-forge-migration.gradle | 122 ++ .../packaged-forge-tinkers.gradle | 266 +++ gradle/verification/packaged-forge.gradle | 372 ++++ gradle/verification/support.gradle | 269 +++ gradle/verification/workflows.gradle | 54 + .../java/com/mcmoddev/alt/BaseMetalsALT.java | 2 +- .../com/mcmoddev/basemetals/BaseMetals.java | 116 +- .../client/config/BaseMetalsConfigScreen.java | 220 ++ .../client/renderer/RenderBaseMetalsBolt.java | 38 + .../basemetals/content/ContentMode.java | 66 + .../basemetals/content/ContentPolicy.java | 244 +++ .../basemetals/content/MaterialForm.java | 92 + .../basemetals/data/MaterialNames.java | 104 +- .../mcmoddev/basemetals/data/TraitNames.java | 189 +- .../com/mcmoddev/basemetals/init/Blocks.java | 17 +- .../com/mcmoddev/basemetals/init/Fluids.java | 11 +- .../mcmoddev/basemetals/init/ItemGroups.java | 24 +- .../com/mcmoddev/basemetals/init/Items.java | 161 +- .../mcmoddev/basemetals/init/Materials.java | 13 +- .../com/mcmoddev/basemetals/init/Recipes.java | 25 +- .../basemetals/init/VillagerTrades.java | 114 +- .../orespawn/BaseMetalsOreSpawn.java | 23 - .../plugins/BMeConstructsArmory.java | 44 +- .../integration/plugins/BMeDenseOres.java | 9 +- .../integration/plugins/BMeEnderIO.java | 32 +- .../integration/plugins/BMeIC2.java | 12 +- .../integration/plugins/BMeMekanism.java | 8 +- .../plugins/BMeThermalExpansion.java | 27 +- .../plugins/BMeTinkersConstruct.java | 146 +- .../integration/plugins/BMeVeinMiner.java | 7 +- .../basemetals/items/ItemBaseMetalsArrow.java | 41 + .../basemetals/items/ItemBaseMetalsBolt.java | 25 + .../basemetals/items/ItemBaseMetalsBow.java | 120 ++ .../items/ItemBaseMetalsCrossbow.java | 140 ++ .../basemetals/items/ItemBaseMetalsHoe.java | 25 + .../items/MaterialRangedDamage.java | 29 + .../loot/ContentModeLootCondition.java | 57 + .../ClientContentModeConnectionHandler.java | 12 + .../network/ContentModeMessage.java | 36 + .../network/ContentModeNetwork.java | 59 + .../properties/AdamantineProperty.java | 126 +- .../properties/AdamantineToolProperty.java | 110 +- .../properties/AquariumProperty.java | 139 +- .../properties/AquariumToolProperty.java | 110 +- .../properties/BMEPropertiesHelper.java | 147 +- .../properties/BMEPropertyBase.java | 96 +- .../properties/ColdIronProperty.java | 119 +- .../properties/ColdIronToolProperty.java | 106 +- .../basemetals/properties/LeadProperty.java | 126 +- .../properties/MithrilProperty.java | 148 +- .../properties/MithrilToolProperty.java | 118 +- .../properties/StarSteelProperty.java | 132 +- .../basemetals/proxy/ClientProxy.java | 30 +- .../basemetals/proxy/CommonProxy.java | 40 +- .../basemetals/proxy/ServerProxy.java | 8 +- .../recipe/ContentAcquisitionFilters.java | 74 + .../recipe/PolicyCrusherRecipe.java | 41 + .../basemetals/recipe/PolicyRecipe.java | 67 + .../mcmoddev/basemetals/util/BMeConfig.java | 179 +- .../basemetals/util/EventHandler.java | 75 +- .../basemetals/util/VillagerTradeHelper.java | 10 +- .../VanillaBitsRegistryEvents.java | 5 - .../basemetals/vanillabits/VanillaBlocks.java | 45 +- .../basemetals/vanillabits/VanillaFluids.java | 2 +- .../basemetals/vanillabits/VanillaItems.java | 143 +- .../basemetals/vanillabits/package-info.java | 10 +- .../worldgen/BaseMetalsWorldgenProvider.java | 92 + .../com/mcmoddev/orespawn/package-info.java | 4 - .../recipes/transportation/rail.json | 44 + .../alt/chests/abandoned_mineshaft.json | 1028 ++++++---- .../basemetals/alt/chests/desert_pyramid.json | 1738 +++++++++------- .../alt/chests/end_city_treasure.json | 1771 ++++++++++------- .../basemetals/alt/chests/jungle_temple.json | 1738 +++++++++------- .../basemetals/alt/chests/nether_bridge.json | 1738 +++++++++------- .../basemetals/alt/chests/simple_dungeon.json | 1738 +++++++++------- .../alt/chests/spawn_bonus_chest.json | 764 ++++--- .../alt/chests/stronghold_corridor.json | 1738 +++++++++------- .../alt/chests/stronghold_crossing.json | 996 +++++---- .../alt/chests/village_blacksmith.json | 1030 ++++++---- .../assets/basemetals/lang/de_de.lang | 65 + .../assets/basemetals/lang/en_au.lang | 65 + .../assets/basemetals/lang/en_ca.lang | 65 + .../assets/basemetals/lang/en_en.lang | 65 + .../assets/basemetals/lang/en_gb.lang | 65 + .../assets/basemetals/lang/en_pt.lang | 65 + .../assets/basemetals/lang/en_us.lang | 65 + .../assets/basemetals/lang/es_es.lang | 65 + .../assets/basemetals/lang/es_mx.lang | 65 + .../assets/basemetals/lang/fr_ca.lang | 65 + .../assets/basemetals/lang/fr_fr.lang | 65 + .../assets/basemetals/lang/it_it.lang | 65 + .../assets/basemetals/lang/ja_jp.lang | 65 + .../assets/basemetals/lang/nl_nl.lang | 65 + .../assets/basemetals/lang/pt_br.lang | 65 + .../assets/basemetals/lang/ru_ru.lang | 65 + .../assets/basemetals/lang/zh_cn.lang | 65 + .../assets/basemetals/lang/zh_tw.lang | 65 + .../basemetals/recipes/activator_rail.json | 3 +- .../basemetals/recipes/detector_rail.json | 13 +- .../basemetals/recipes/diamond_door.json | 1 + .../basemetals/recipes/emerald_door.json | 1 + .../assets/basemetals/recipes/gold_door.json | 1 + .../basemetals/recipes/quartz_door.json | 1 + .../basemetals/recipes/quartz_trapdoor.json | 5 +- .../assets/basemetals/recipes/rail.json | 3 +- .../textures/blocks/mercury_flow.png.mcmeta | 4 +- .../textures/blocks/mercury_still.png.mcmeta | 10 +- .../minecraft/models/item/acacia_door.json | 14 +- .../minecraft/models/item/birch_door.json | 14 +- .../minecraft/models/item/dark_oak_door.json | 14 +- .../minecraft/models/item/iron_door.json | 14 +- .../minecraft/models/item/jungle_door.json | 14 +- .../minecraft/models/item/oak_door.json | 14 +- .../minecraft/models/item/spruce_door.json | 14 +- .../config/BaseMetalsConfigScreenTest.java | 78 + ...ientExtensionRegistrationContractTest.java | 39 + .../ConfigLocalizationContractTest.java | 111 ++ .../renderer/BoltRendererContractTest.java | 69 + .../basemetals/content/ContentPolicyTest.java | 157 ++ .../data/DoorRecipeContractTest.java | 112 ++ .../data/LootPolicyContractTest.java | 66 + .../data/OreSpawnProviderContractTest.java | 203 ++ .../data/RailRecipeAdvancementTest.java | 78 + .../mcmoddev/basemetals/init/BlocksTests.java | 36 - .../network/ContentModeNetworkTest.java | 33 + .../BaseMetalsClientConfigRuntimeProbe.java | 79 + .../test/BaseMetalsRuntimeProbe.java | 1249 +++++++++++- .../test/BaseMetalsTinkersRuntimeProbe.java | 346 ++++ .../util/BaseMetalsConfigContractTest.java | 196 ++ .../basemetals/util/TestConfigFactory.java | 30 + .../com/mcmoddev/lib/util/ConfigTests.java | 18 +- .../orespawn3/basemetals-custom.json | 264 +++ .../orespawn3/basemetals-stock.json} | 2 +- 149 files changed, 19150 insertions(+), 8228 deletions(-) create mode 100644 docs/configuration.md create mode 100644 docs/examples/basemetals-orespawn-disabled.json create mode 100644 docs/world-generation.md create mode 100644 gradle/README.md create mode 100644 gradle/dependencies.gradle create mode 100644 gradle/ide/eclipse.gradle create mode 100644 gradle/release/artifacts.gradle create mode 100644 gradle/release/publishing.gradle create mode 100644 gradle/verification/packaged-forge-cofh.gradle create mode 100644 gradle/verification/packaged-forge-dependencies.gradle create mode 100644 gradle/verification/packaged-forge-migration.gradle create mode 100644 gradle/verification/packaged-forge-tinkers.gradle create mode 100644 gradle/verification/packaged-forge.gradle create mode 100644 gradle/verification/support.gradle create mode 100644 gradle/verification/workflows.gradle create mode 100644 src/main/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen.java create mode 100644 src/main/java/com/mcmoddev/basemetals/client/renderer/RenderBaseMetalsBolt.java create mode 100644 src/main/java/com/mcmoddev/basemetals/content/ContentMode.java create mode 100644 src/main/java/com/mcmoddev/basemetals/content/ContentPolicy.java create mode 100644 src/main/java/com/mcmoddev/basemetals/content/MaterialForm.java delete mode 100644 src/main/java/com/mcmoddev/basemetals/integration/orespawn/BaseMetalsOreSpawn.java create mode 100644 src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsArrow.java create mode 100644 src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBolt.java create mode 100644 src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBow.java create mode 100644 src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsCrossbow.java create mode 100644 src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsHoe.java create mode 100644 src/main/java/com/mcmoddev/basemetals/items/MaterialRangedDamage.java create mode 100644 src/main/java/com/mcmoddev/basemetals/loot/ContentModeLootCondition.java create mode 100644 src/main/java/com/mcmoddev/basemetals/network/ClientContentModeConnectionHandler.java create mode 100644 src/main/java/com/mcmoddev/basemetals/network/ContentModeMessage.java create mode 100644 src/main/java/com/mcmoddev/basemetals/network/ContentModeNetwork.java create mode 100644 src/main/java/com/mcmoddev/basemetals/recipe/ContentAcquisitionFilters.java create mode 100644 src/main/java/com/mcmoddev/basemetals/recipe/PolicyCrusherRecipe.java create mode 100644 src/main/java/com/mcmoddev/basemetals/recipe/PolicyRecipe.java create mode 100644 src/main/java/com/mcmoddev/basemetals/worldgen/BaseMetalsWorldgenProvider.java delete mode 100644 src/main/java/com/mcmoddev/orespawn/package-info.java create mode 100644 src/main/resources/assets/basemetals/advancements/recipes/transportation/rail.json create mode 100644 src/test/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreenTest.java create mode 100644 src/test/java/com/mcmoddev/basemetals/client/config/ClientExtensionRegistrationContractTest.java create mode 100644 src/test/java/com/mcmoddev/basemetals/client/config/ConfigLocalizationContractTest.java create mode 100644 src/test/java/com/mcmoddev/basemetals/client/renderer/BoltRendererContractTest.java create mode 100644 src/test/java/com/mcmoddev/basemetals/content/ContentPolicyTest.java create mode 100644 src/test/java/com/mcmoddev/basemetals/data/DoorRecipeContractTest.java create mode 100644 src/test/java/com/mcmoddev/basemetals/data/LootPolicyContractTest.java create mode 100644 src/test/java/com/mcmoddev/basemetals/data/OreSpawnProviderContractTest.java create mode 100644 src/test/java/com/mcmoddev/basemetals/data/RailRecipeAdvancementTest.java delete mode 100644 src/test/java/com/mcmoddev/basemetals/init/BlocksTests.java create mode 100644 src/test/java/com/mcmoddev/basemetals/network/ContentModeNetworkTest.java create mode 100644 src/test/java/com/mcmoddev/basemetals/test/BaseMetalsClientConfigRuntimeProbe.java create mode 100644 src/test/java/com/mcmoddev/basemetals/test/BaseMetalsTinkersRuntimeProbe.java create mode 100644 src/test/java/com/mcmoddev/basemetals/util/BaseMetalsConfigContractTest.java create mode 100644 src/test/java/com/mcmoddev/basemetals/util/TestConfigFactory.java create mode 100644 src/test/resources/orespawn3/basemetals-custom.json rename src/{main/resources/assets/basemetals/orespawn/basemetals.json => test/resources/orespawn3/basemetals-stock.json} (99%) diff --git a/.editorconfig b/.editorconfig index 7c2ae4c0..bbf165be 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,5 +10,8 @@ indent_style = tab indent_size = 4 trim_trailing_whitespace = true +[*.bat] +end_of_line = crlf + [*.md] trim_trailing_whitespace = false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6104faf6..9658c400 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -177,9 +177,9 @@ jobs: if-no-files-found: error retention-days: 30 path: | - build/libs/BaseMetals-2.5.1.112021.jar - build/libs/BaseMetals-2.5.1.112021-sources.jar - build/libs/BaseMetals-2.5.1.112021-javadoc.jar + build/libs/BaseMetals-2.6.0.112021.jar + build/libs/BaseMetals-2.6.0.112021-sources.jar + build/libs/BaseMetals-2.6.0.112021-javadoc.jar build/release/SHA256SUMS CHANGELOG.txt diff --git a/README.md b/README.md index 600a852e..773e1716 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,19 @@ Also known as a sledgehammer, this tool is designed for pulverizing rocks. Using ## Requirements -This mod requires that you install Minecraft Forge version 1.12-14.21.1.2387 or later (earlier versions of Forge for Minecraft 1.12 may work, but no guarantees). +Base Metals 2.6.0 requires Minecraft 1.12.2, Forge 14.23.5.2859, MMDLib, +and OreSpawn 4.1.0.112021 or newer in the 4.x line. + +OreSpawn 4.1's Mods directory includes a Base Metals cog for editing the +existing `BaseMetals.cfg`. See [configuration](docs/configuration.md) for the +restart and ore-rule safety behavior, including the upgrade-safe High Fantasy, +Low Fantasy, and Realism content modes. Existing configurations without a mode +remain in High Fantasy and keep the historical recipes and acquisition paths. + +OreSpawn is the sole Base Metals ore generator. To disable Base Metals' rules +for a CoFH World or other custom-worldgen setup, follow the +[world-generation guide](docs/world-generation.md). The old MMDLib +`using_orespawn` and `fallback_orespawn` options do not control these rules. diff --git a/build.gradle b/build.gradle index c4248437..5d92b0c6 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,3 @@ -import groovy.json.JsonSlurper -import java.nio.charset.StandardCharsets -import java.security.MessageDigest -import java.util.jar.Manifest -import java.util.zip.ZipFile import org.apache.tools.ant.filters.FixCrLfFilter plugins { @@ -202,126 +197,7 @@ repositories { } } -def curseCoordinate = { String slug, String projectId, String fileId -> - "curse.maven:${slug}-${projectId}:${fileId}".toString() -} - -def dependencySpecs = [ - mmdlib: [ - coordinate: curseCoordinate('mmdlib', project.mmdlib_curse_project_id, project.mmdlib_curse_file_id), - version: project.mmdlib_version, sha256: project.mmdlib_sha256, required: true - ], - orespawn3: [ - coordinate: curseCoordinate('mmd-orespawn', project.orespawn3_curse_project_id, project.orespawn3_curse_file_id), - version: project.orespawn3_version, sha256: project.orespawn3_sha256, required: true - ], - alt: [ - coordinate: curseCoordinate('additional-loot-tables', project.alt_curse_project_id, project.alt_curse_file_id), - version: project.alt_version, sha256: project.alt_sha256, required: false - ], - mantle: [ - coordinate: curseCoordinate('mantle', project.mantle_curse_project_id, project.mantle_curse_file_id), - version: project.mantle_version, sha256: project.mantle_sha256, required: false - ], - tconstruct: [ - coordinate: curseCoordinate('tinkers-construct', project.tconstruct_curse_project_id, project.tconstruct_curse_file_id), - version: project.tconstruct_version, sha256: project.tconstruct_sha256, required: false - ], - conarm: [ - coordinate: curseCoordinate('constructs-armory', project.conarm_curse_project_id, project.conarm_curse_file_id), - version: project.conarm_version, sha256: project.conarm_sha256, required: false - ], - thaumcraft: [ - coordinate: curseCoordinate('thaumcraft', project.thaumcraft_curse_project_id, project.thaumcraft_curse_file_id), - version: project.thaumcraft_version, sha256: project.thaumcraft_sha256, required: false - ], - baubles: [ - coordinate: curseCoordinate('baubles', project.baubles_curse_project_id, project.baubles_curse_file_id), - version: project.baubles_version, sha256: project.baubles_sha256, required: false - ], - cofhcore: [ - coordinate: curseCoordinate('cofh-core', project.cofhcore_curse_project_id, project.cofhcore_curse_file_id), - version: project.cofhcore_version, sha256: project.cofhcore_sha256, required: false - ] -] - -configurations { - orespawn3Development { - canBeConsumed = false - canBeResolved = true - transitive = false - } - legacyDependencyArtifacts { - canBeConsumed = false - canBeResolved = true - transitive = false - } - legacyBaselineArtifact { - canBeConsumed = false - canBeResolved = true - transitive = false - } - orespawn4CompatibilityArtifact { - canBeConsumed = false - canBeResolved = true - transitive = false - } -} - -def mmdlibDevelopmentDependency = renamer.dependency(dependencySpecs.mmdlib.coordinate) -def orespawn3DevelopmentDependency = renamer.dependency(dependencySpecs.orespawn3.coordinate) - -def sanitizedOrespawn3DevelopmentJar = tasks.register('sanitizedOrespawn3DevelopmentJar', Jar) { - group = 'ide' - description = 'Removes stale release signatures from the MCP-remapped OreSpawn 3 development jar.' - inputs.files(configurations.orespawn3Development) - archiveFileName = "OreSpawn-${project.orespawn3_version}-development.jar" - destinationDirectory = layout.buildDirectory.dir('development-dependencies') - includeEmptyDirs = false - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - from({ - configurations.orespawn3Development.files.collect { dependency -> zipTree(dependency) } - }) { - exclude 'META-INF/MANIFEST.MF' - exclude 'META-INF/*.SF' - exclude 'META-INF/*.RSA' - exclude 'META-INF/*.DSA' - } -} - -dependencies { - implementation minecraft.dependency( - "net.minecraftforge:forge:${project.minecraft_version}-${project.forge_version}") - compileOnly 'org.lwjgl.lwjgl:lwjgl_util:2.9.4-nightly-20150209' - - implementation mmdlibDevelopmentDependency - orespawn3Development orespawn3DevelopmentDependency - compileOnly files(sanitizedOrespawn3DevelopmentJar.flatMap { it.archiveFile }) - runtimeOnly files(sanitizedOrespawn3DevelopmentJar.flatMap { it.archiveFile }) - - compileOnly renamer.dependency(dependencySpecs.alt.coordinate) - compileOnly renamer.dependency(dependencySpecs.mantle.coordinate) - compileOnly renamer.dependency(dependencySpecs.tconstruct.coordinate) - compileOnly renamer.dependency(dependencySpecs.conarm.coordinate) - compileOnly renamer.dependency(dependencySpecs.thaumcraft.coordinate) - compileOnly renamer.dependency(dependencySpecs.baubles.coordinate) - compileOnly renamer.dependency(dependencySpecs.cofhcore.coordinate) - - dependencySpecs.each { name, spec -> - legacyDependencyArtifacts spec.coordinate - } - legacyBaselineArtifact curseCoordinate('base-metals', - project.legacy_basemetals_curse_project_id, - project.legacy_basemetals_curse_file_id) - orespawn4CompatibilityArtifact curseCoordinate('mmd-orespawn', - project.orespawn4_curse_project_id, - project.orespawn4_curse_file_id) - - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.2' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.10.2' - testImplementation 'org.mockito:mockito-core:2.28.2' -} +apply from: 'gradle/dependencies.gradle' // Renamer Gradle replaces ForgeGradle's retired deobfProvided configuration. // Dependencies are mapped from their production SRG names to stable_39 for the @@ -405,1030 +281,19 @@ tasks.named('assemble') { dependsOn tasks.named('javadocJar') } -def java8Launcher = javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(8) - vendor = JvmVendorSpec.ADOPTIUM -} - -def java25Launcher = javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(25) - vendor = JvmVendorSpec.ADOPTIUM -} - -tasks.register('verifyReleaseToolchains') { - group = 'verification' - description = 'Requires the pinned Gradle, Mavenizer, compilation, and runtime JDKs.' - doLast { - String gradleVendor = System.getProperty('java.vendor') - String gradleRuntime = System.getProperty('java.runtime.version') - if (project.gradle_java_version != '17' - || gradleVendor != 'Eclipse Adoptium' - || gradleRuntime != '17.0.1+12') { - throw new GradleException("Expected Gradle on Temurin 17.0.1+12, found " - + "${gradleVendor} ${gradleRuntime} at ${System.getProperty('java.home')}") - } - - def metadata = java8Launcher.get().metadata - if (project.java_toolchain_version != '8.0.502+7' - || metadata.vendor.toString() != 'Eclipse Temurin' - || metadata.javaRuntimeVersion != '1.8.0_502-b07') { - throw new GradleException("Expected Temurin ${project.java_toolchain_version}, found " - + "${metadata.vendor} ${metadata.javaRuntimeVersion} at ${metadata.installationPath}") - } - - def mavenizerMetadata = java25Launcher.get().metadata - if (project.mavenizer_java_version != '25.0.3+9' - || mavenizerMetadata.vendor.toString() != 'Eclipse Temurin' - || mavenizerMetadata.javaRuntimeVersion != '25.0.3+9-LTS') { - throw new GradleException("Expected Mavenizer on Temurin ${project.mavenizer_java_version}, found " - + "${mavenizerMetadata.vendor} ${mavenizerMetadata.javaRuntimeVersion} " - + "at ${mavenizerMetadata.installationPath}") - } - } -} - -tasks.named('check') { - dependsOn tasks.named('verifyReleaseToolchains') -} - -def expectedReleaseFiles = providers.provider { - def prefix = "${base.archivesName.get()}-${project.version}" - [ - "${prefix}.jar", - "${prefix}-sources.jar", - "${prefix}-javadoc.jar" - ] -} -def preparedReleaseDir = providers.gradleProperty('preparedReleaseDir') - -def sha256 = { File candidate -> - MessageDigest digest = MessageDigest.getInstance('SHA-256') - candidate.withInputStream { input -> - byte[] buffer = new byte[8192] - for (int read = input.read(buffer); read >= 0; read = input.read(buffer)) { - if (read > 0) digest.update(buffer, 0, read) - } - } - digest.digest().encodeHex().toString().toUpperCase() -} - -tasks.register('verifyReleaseConfiguration') { - group = 'verification' - description = 'Validates the complete Base Metals 1.12 release identity and dependency contract.' - dependsOn tasks.named('verifyReleaseToolchains') - doLast { - if (project.mod_version != '2.5.1.112021' - || project.minecraft_version != '1.12.2' - || project.forge_version != '14.23.5.2859' - || project.mappings_channel != 'stable' - || project.mappings_version != '39-1.12') { - throw new GradleException('Unexpected Base Metals version, Minecraft, Forge, or mappings target') - } - String buildScript = file('build.gradle').getText('UTF-8') - String settingsScript = file('settings.gradle').getText('UTF-8') - Properties wrapper = new Properties() - file('gradle/wrapper/gradle-wrapper.properties').withInputStream { wrapper.load(it) } - if (!buildScript.contains("id 'net.minecraftforge.gradle' version '7.0.34'") - || !buildScript.contains("id 'net.minecraftforge.renamer' version '1.1.5'") - || !settingsScript.contains("version '1.0.0'") - || wrapper.getProperty('distributionUrl') - != 'https://services.gradle.org/distributions/gradle-9.6.1-bin.zip' - || wrapper.getProperty('distributionSha256Sum') - != '9c0f7faeeb306cb14e4279a3e084ca6b596894089a0638e68a07c945a32c9e14') { - throw new GradleException('ForgeGradle, Renamer, Foojay, or Gradle wrapper identity drifted') - } - if (project.loader_name != 'forge' || project.loader_code != '1' - || project.java_version != '8' - || project.java_toolchain_version != '8.0.502+7' - || project.gradle_java_version != '17' - || project.mavenizer_java_version != '25.0.3+9') { - throw new GradleException('Unexpected loader or Java release metadata') - } - if (project.mod_group != expectedMavenGroup - || base.archivesName.get() != expectedMavenArtifact - || "${project.group}:${base.archivesName.get()}:${project.version}" != expectedMavenCoordinate) { - throw new GradleException("Unexpected Maven coordinate; expected ${expectedMavenCoordinate}") - } - if (project.cf_project_id != '240967' - || project.cf_requirements != 'mmd-orespawn,mmdlib' - || project.cf_versions != '1.12.2') { - throw new GradleException('Unexpected CurseForge publication contract') - } - if (dependencySpecs.mmdlib.version != '1.0.0-rc2.36' - || dependencySpecs.orespawn3.version != '3.3.1.179') { - throw new GradleException('Unexpected primary MMDLib or OreSpawn 3 version') - } - String source = file('src/main/java/com/mcmoddev/basemetals/BaseMetals.java').getText('UTF-8') - if (!source.contains('VERSION = "2.5.1.112021"') - || !source.contains('certificateFingerprint = ""')) { - throw new GradleException('Base Metals source version or unsigned fingerprint contract drifted') - } - } -} - -tasks.register('verifyReleaseDependencies') { - group = 'verification' - description = 'Resolves and checksum-verifies all exact legacy mod dependencies.' - dependsOn tasks.named('verifyReleaseConfiguration') - doLast { - def resolved = configurations.legacyDependencyArtifacts.resolvedConfiguration.resolvedArtifacts - if (resolved.size() != dependencySpecs.size()) { - throw new GradleException("Expected ${dependencySpecs.size()} exact legacy artifacts, found ${resolved.size()}") - } - dependencySpecs.each { name, spec -> - def bits = spec.coordinate.split(':') - def matches = resolved.findAll { - it.moduleVersion.id.group == bits[0] - && it.moduleVersion.id.name == bits[1] - && it.moduleVersion.id.version == bits[2] - } - if (matches.size() != 1) { - throw new GradleException("Expected exactly ${spec.coordinate}, found ${matches*.moduleVersion*.id}") - } - String actual = sha256(matches.first().file) - if (actual != spec.sha256) { - throw new GradleException("${name} SHA-256 is ${actual}, expected ${spec.sha256}") - } - } - def orespawn4 = configurations.orespawn4CompatibilityArtifact - .resolvedConfiguration.resolvedArtifacts - if (orespawn4.size() != 1 - || sha256(orespawn4.first().file) != project.orespawn4_sha256) { - throw new GradleException('OreSpawn 4 compatibility artifact is missing or has the wrong SHA-256') - } - ZipFile compatibilityJar = new ZipFile(orespawn4.first().file) - try { - def entry = compatibilityJar.getEntry('mcmod.info') - def metadata = entry == null ? null : new JsonSlurper().parseText( - compatibilityJar.getInputStream(entry).getText(StandardCharsets.UTF_8.name())) - def mod = metadata instanceof List ? metadata.find { it.modid == 'orespawn' } : metadata - if (mod == null || mod.version != project.orespawn4_version) { - throw new GradleException("OreSpawn 4 compatibility artifact is not ${project.orespawn4_version}") - } - } finally { - compatibilityJar.close() - } - } -} - -tasks.register('verifyJsonResources') { - group = 'verification' - description = 'Parses every production JSON resource.' - inputs.files(fileTree('src/main/resources') { include '**/*.json' }) - doLast { - fileTree('src/main/resources') { include '**/*.json' }.files.sort().each { candidate -> - try { - new JsonSlurper().parse(candidate) - } catch (Exception failure) { - throw new GradleException("Invalid JSON resource ${project.relativePath(candidate)}", failure) - } - } - } -} - -tasks.named('check') { - dependsOn tasks.named('verifyReleaseConfiguration') - dependsOn tasks.named('verifyReleaseDependencies') - dependsOn tasks.named('verifyJsonResources') -} - -tasks.register('verifyHistoricalOreSpawnConfiguration') { - group = 'verification' - description = 'Locks the eleven-rule OreSpawn 3 data contract and fallback hand-off behavior.' - inputs.file('src/main/resources/assets/basemetals/orespawn/basemetals.json') - inputs.file('src/main/java/com/mcmoddev/basemetals/integration/orespawn/BaseMetalsOreSpawn.java') - doLast { - def config = new JsonSlurper().parse( - file('src/main/resources/assets/basemetals/orespawn/basemetals.json')) - List expectedRules = [ - 'coldiron_ore', 'adamantine_ore', 'starsteel_ore', 'copper_ore', - 'silver_ore', 'tin_ore', 'lead_ore', 'zinc_ore', 'mercury_ore', - 'nickel_ore', 'platinum_ore' - ].sort() - if (config.version != '2.0' || config.spawns.keySet().sort() != expectedRules) { - throw new GradleException('The packaged OreSpawn 3 configuration is not the eleven-rule legacy contract') - } - config.spawns.each { name, rule -> - if (!rule.enabled || rule.retrogen || rule.blocks.size() != 1 - || rule.blocks.first().name != "basemetals:${name}") { - throw new GradleException("Historical OreSpawn rule ${name} changed shape") - } - } - String plugin = file('src/main/java/com/mcmoddev/basemetals/integration/orespawn/BaseMetalsOreSpawn.java') - .getText('UTF-8') - if (!plugin.contains('@OreSpawnPlugin(modid = BaseMetals.MODID') - || !plugin.contains('resourcePath = SharedStrings.ORESPAWN_MODID') - || plugin.contains('package com.mcmoddev.orespawn;')) { - throw new GradleException('The OreSpawn 3 plugin discovery contract changed') - } - } -} - -tasks.named('check') { - dependsOn tasks.named('verifyHistoricalOreSpawnConfiguration') -} - -tasks.register('verifyReleaseArtifacts') { - group = 'verification' - description = 'Audits deterministic jars, legacy inventory, bytecode, metadata, and package isolation.' - dependsOn tasks.named('assemble') - dependsOn tasks.named('verifyReleaseDependencies') - doLast { - File libs = layout.buildDirectory.dir('libs').get().asFile - List expected = expectedReleaseFiles.get().sort() - List jars = (libs.listFiles() ?: [] as File[]) - .findAll { it.name.endsWith('.jar') } - .sort { it.name } - if (jars.collect { it.name } != expected || jars.any { it.length() == 0L }) { - throw new GradleException("Release directory must contain exactly ${expected}; found ${jars*.name}") - } - - File mainJar = new File(libs, "BaseMetals-${project.version}.jar") - ZipFile zip = new ZipFile(mainJar) - try { - List names = zip.entries().collect { it.name } - List forbiddenNames = names.findAll { name -> - name.startsWith('com/mcmoddev/lib/') - || name.startsWith('net/minecraft/') - || name.startsWith('net/minecraftforge/') - || name.startsWith('org/junit/') - || name.contains('/test/') - || name.toLowerCase().contains('fixture') - || name.toLowerCase().contains('agent') - || name.toLowerCase().contains('runtimeprobe') - } - if (!forbiddenNames.isEmpty()) { - throw new GradleException("Release jar contains forbidden entries: ${forbiddenNames.take(20)}") - } - - zip.entries().findAll { it.name.endsWith('.class') }.each { entry -> - byte[] header = new byte[8] - zip.getInputStream(entry).withCloseable { input -> - if (input.read(header) != header.length) { - throw new GradleException("Cannot inspect bytecode header for ${entry.name}") - } - } - int major = ((header[6] & 0xff) << 8) | (header[7] & 0xff) - if (major != 52) { - throw new GradleException("${entry.name} uses Java class major ${major}, expected 52") - } - } - - def manifestEntry = zip.getEntry('META-INF/MANIFEST.MF') - def manifest = manifestEntry == null ? null - : new Manifest(zip.getInputStream(manifestEntry)).mainAttributes - if (manifest == null - || manifest.getValue('Maven-Artifact') != expectedMavenCoordinate - || manifest.getValue('Implementation-Version') != project.mod_version - || manifest.getValue('Timestamp') != null - || manifest.getValue('Built-On') != '1.12.2-14.23.5.2859') { - throw new GradleException('Release manifest identity is incomplete or volatile') - } - - def metadataEntry = zip.getEntry('mcmod.info') - if (metadataEntry == null) { - throw new GradleException('Release jar is missing mcmod.info') - } - def metadata = new JsonSlurper().parseText( - zip.getInputStream(metadataEntry).getText(StandardCharsets.UTF_8.name())) - def mod = metadata instanceof List ? metadata.find { it.modid == 'basemetals' } : metadata - if (mod == null || mod.version != project.mod_version || mod.mcversion != project.minecraft_version) { - throw new GradleException('Packaged mcmod.info has the wrong mod or target version') - } - - List leakedPaths = [] - zip.entries().findAll { entry -> archiveTextSuffixes.any { entry.name.endsWith(it) } }.each { entry -> - String text = zip.getInputStream(entry).getText(StandardCharsets.UTF_8.name()) - if (text =~ /(?i)([A-Z]:\\Users\\|[A-Z]:\\BaseMetals|\/home\/runner\/|\/Users\/)/) { - leakedPaths.add(entry.name) - } - } - if (!leakedPaths.isEmpty()) { - throw new GradleException("Release jar leaks local paths in ${leakedPaths}") - } - } finally { - zip.close() - } - - def baselineArtifacts = configurations.legacyBaselineArtifact.resolvedConfiguration.resolvedArtifacts - if (baselineArtifacts.size() != 1) { - throw new GradleException("Expected one released Base Metals baseline, found ${baselineArtifacts.size()}") - } - File baseline = baselineArtifacts.first().file - String baselineHash = sha256(baseline) - if (baselineHash != project.legacy_basemetals_sha256) { - throw new GradleException("Released baseline SHA-256 is ${baselineHash}, expected " - + project.legacy_basemetals_sha256) - } - def entryInventory = { File jarFile -> - ZipFile candidate = new ZipFile(jarFile) - try { - candidate.entries().findAll { !it.isDirectory() }.collect { it.name }.sort() - } finally { - candidate.close() - } - } - List currentInventory = entryInventory(mainJar) - List legacyInventory = entryInventory(baseline) - List allowedAddedEntries = [ - 'assets/mmdlib/lang/en_us.lang', - 'assets/mmdlib/lang/es_es.lang', - // Avoid Java's package-signer collision with signed OreSpawn - // while preserving the plugin annotation and resource path. - 'com/mcmoddev/basemetals/integration/orespawn/BaseMetalsOreSpawn.class' - ] - List allowedRemovedEntries = [ - // The historical CurseForge jar was signed and carried FML's - // generated cache. Neither belongs in a reproducible rebuild. - 'META-INF/MINECRAF.RSA', - 'META-INF/MINECRAF.SF', - 'META-INF/fml_cache_annotation.json', - 'META-INF/fml_cache_class_versions.json', - 'com/mcmoddev/orespawn/BaseMetalsOreSpawn.class', - // These source files were deliberately removed on master-1.12 - // after 2.5.0-rc2.332; the modernization does not resurrect them. - 'com/mcmoddev/basemetals/items/MMDToolEffects.class', - 'com/mcmoddev/basemetals/items/package-info.class' - ] - List unexpectedAdded = (currentInventory - legacyInventory) - allowedAddedEntries - List unexpectedRemoved = (legacyInventory - currentInventory) - allowedRemovedEntries - if (!unexpectedAdded.isEmpty() || !unexpectedRemoved.isEmpty() - || !allowedAddedEntries.every { currentInventory.contains(it) } - || !allowedRemovedEntries.every { legacyInventory.contains(it) }) { - throw new GradleException("Release inventory drifted from ${project.legacy_basemetals_version}; " - + "added=${unexpectedAdded.take(20)}, removed=${unexpectedRemoved.take(20)}") - } - } -} - -tasks.register('writeReleaseChecksums') { - group = 'verification' - description = 'Writes SHA-256 checksums for the audited release jars.' - dependsOn tasks.named('verifyReleaseArtifacts') - def outputFile = layout.buildDirectory.file('release/SHA256SUMS') - inputs.files(providers.provider { - expectedReleaseFiles.get().collect { name -> - layout.buildDirectory.file("libs/${name}").get().asFile - } - }) - outputs.file(outputFile) - doLast { - File output = outputFile.get().asFile - output.parentFile.mkdirs() - File libs = layout.buildDirectory.dir('libs').get().asFile - String contents = expectedReleaseFiles.get().sort().collect { name -> - "${sha256(new File(libs, name))} ${name}" - }.join(System.lineSeparator()) + System.lineSeparator() - output.setText(contents, 'UTF-8') - } -} - -tasks.register('verifyPreparedReleaseArtifacts') { - group = 'verification' - description = 'Audits a previously built immutable release bundle before publication.' - doLast { - if (!preparedReleaseDir.isPresent()) { - throw new GradleException('preparedReleaseDir is required for prepared artifact publication') - } - File prepared = file(preparedReleaseDir.get()) - List expected = expectedReleaseFiles.get().sort() - List jars = (prepared.listFiles() ?: [] as File[]) - .findAll { it.name.endsWith('.jar') }.sort { it.name } - if (jars.collect { it.name } != expected || jars.any { it.length() == 0L }) { - throw new GradleException("Prepared release must contain exactly ${expected}") - } - File checksums = new File(prepared, 'SHA256SUMS') - File changelog = new File(prepared, 'CHANGELOG.txt') - if (!checksums.isFile() || !changelog.isFile()) { - throw new GradleException('Prepared release is missing SHA256SUMS or CHANGELOG.txt') - } - List actual = jars.collect { "${sha256(it)} ${it.name}" }.sort() - List declared = checksums.readLines('UTF-8').findAll { !it.trim().isEmpty() }.sort() - if (actual != declared) { - throw new GradleException('Prepared release checksums do not match the immutable jars') - } - } -} - -tasks.register('runtimeProbeJar', Jar) { - group = 'verification' - description = 'Builds the mapped test-only packaged-runtime acceptance probe.' - dependsOn tasks.named('testClasses') - archiveBaseName = 'basemetals-runtime-probe' - archiveVersion = '' - archiveClassifier = 'deobf' - destinationDirectory = layout.buildDirectory.dir('runtime-probes-dev') - from(sourceSets.test.output) { - include 'com/mcmoddev/basemetals/test/BaseMetalsRuntimeProbe*.class' - } -} - -def packagedRuntimeProbeJar = renamer.classes(tasks.named('runtimeProbeJar', Jar)) { - map.from minecraft.dependency.toSrgFile - archiveClassifier = null - output = layout.buildDirectory.file('runtime-probes/basemetals-runtime-probe.jar') -} - -tasks.register('packagedRuntimeProbes') { - group = 'verification' - dependsOn packagedRuntimeProbeJar -} - -def packagedForgeRuntimeRoot = providers.gradleProperty('packagedForgeRuntimeRoot') -def validatePackagedForgeRoot = { - if (!packagedForgeRuntimeRoot.isPresent()) { - throw new GradleException('packagedForgeRuntimeRoot is required for packaged Forge qualification') - } - File root = file(packagedForgeRuntimeRoot.get()) - [ - new File(root, "forge-${project.minecraft_version}-${project.forge_version}-universal.jar"), - new File(root, "minecraft_server.${project.minecraft_version}.jar"), - new File(root, 'libraries') - ].each { required -> - if (!required.exists()) { - throw new GradleException("Packaged Forge runtime is missing ${required}") - } - } - root -} - -def originalArtifact = { Configuration configuration, String coordinate -> - String[] bits = coordinate.split(':') - def matches = configuration.resolvedConfiguration.resolvedArtifacts.findAll { - it.moduleVersion.id.group == bits[0] - && it.moduleVersion.id.name == bits[1] - && it.moduleVersion.id.version == bits[2] - } - if (matches.size() != 1) { - throw new GradleException("Expected exactly ${coordinate}, found ${matches*.moduleVersion*.id}") - } - matches.first().file -} - -def runtimeLogFailures = { File runDirectory -> - List fatalMarkers = [ - 'Encountered an unexpected exception', 'LoaderException', 'NoClassDefFoundError', - 'NoSuchMethodError', 'NoSuchFieldError', 'IllegalAccessError', 'LinkageError', - 'Exception stopping the server', 'The following mod(s) have been identified as potential causes' - ] - List failures = [] - fileTree(runDirectory) { - include 'logs/**/*.log' - include '*-console.txt' - }.files.each { log -> - int lineNumber = 0 - log.eachLine('UTF-8') { line -> - lineNumber++ - if (fatalMarkers.any { line.contains(it) }) { - failures.add("${log.name}:${lineNumber}: ${line}") - } - } - } - failures -} - -def packagedStacks = [ - Os3: [ - display: 'OreSpawn 3', - artifactVersion: project.orespawn3_version, - modVersion: '3.3.1', - configuration: configurations.legacyDependencyArtifacts, - coordinate: dependencySpecs.orespawn3.coordinate - ], - Os4: [ - display: 'OreSpawn 4 compatibility', - artifactVersion: project.orespawn4_version, - modVersion: project.orespawn4_version, - configuration: configurations.orespawn4CompatibilityArtifact, - coordinate: curseCoordinate('mmd-orespawn', - project.orespawn4_curse_project_id, project.orespawn4_curse_file_id) - ] -] - -packagedStacks.each { stackName, stack -> - File runDirectory = file("${buildDir}/packaged-forge-${stackName.toLowerCase()}-run") - File marker = new File(runDirectory, 'basemetals-runtime-probe.properties') - def prepareTask = tasks.register("preparePackagedForge${stackName}Runtime") { - group = 'verification' - dependsOn releaseJar - dependsOn packagedRuntimeProbeJar - dependsOn tasks.named('verifyReleaseDependencies') - doLast { - delete runDirectory - File sourceRuntime = validatePackagedForgeRoot() - File forge = new File(sourceRuntime, - "forge-${project.minecraft_version}-${project.forge_version}-universal.jar") - java.util.jar.JarFile forgeJar = new java.util.jar.JarFile(forge) - String declaredClasspath - try { - declaredClasspath = forgeJar.manifest.mainAttributes.getValue('Class-Path') - } finally { - forgeJar.close() - } - if (declaredClasspath == null || declaredClasspath.trim().isEmpty()) { - throw new GradleException("Forge runtime has no Class-Path manifest entry: ${forge}") - } - copy { from forge; into runDirectory } - copy { - from new File(sourceRuntime, "minecraft_server.${project.minecraft_version}.jar") - into runDirectory - } - declaredClasspath.trim().split(/\s+/).findAll { - it != "minecraft_server.${project.minecraft_version}.jar" - }.each { String entry -> - String relative = entry.startsWith('libraries/') - ? entry.substring('libraries/'.length()) : entry - File dependency = new File(sourceRuntime, "libraries/${relative}") - if (!dependency.isFile()) { - throw new GradleException("Forge runtime dependency is missing: ${dependency}") - } - copy { from dependency; into new File(runDirectory, "libraries/${relative}").parentFile } - } - File mods = new File(runDirectory, 'mods') - mods.mkdirs() - copy { from layout.buildDirectory.file("libs/BaseMetals-${project.version}.jar"); into mods } - copy { from layout.buildDirectory.file('runtime-probes/basemetals-runtime-probe.jar'); into mods } - copy { - from originalArtifact(configurations.legacyDependencyArtifacts, - dependencySpecs.mmdlib.coordinate) - into mods - } - copy { from originalArtifact(stack.configuration, stack.coordinate); into mods } - new File(runDirectory, 'server.properties').setText('''\ -level-name=world -level-seed=basemetals-release-modernization -level-type=default -online-mode=false -server-port=0 -allow-nether=false -generate-structures=false -spawn-protection=0 -max-tick-time=-1 -''', 'UTF-8') - new File(runDirectory, 'eula.txt').setText('eula=true\n', 'UTF-8') - } - } - - def previous = prepareTask - ['Fresh', 'Reload'].each { phase -> - def dependencyTask = previous - def processTask = tasks.register("packagedForge${stackName}${phase}Process", Exec) { - group = 'verification' - dependsOn dependencyTask - workingDir runDirectory - ByteArrayOutputStream console = new ByteArrayOutputStream() - doFirst { - console.reset() - marker.delete() - File javaExecutable = java8Launcher.get().executablePath.asFile - File forge = new File(runDirectory, - "forge-${project.minecraft_version}-${project.forge_version}-universal.jar") - commandLine javaExecutable, - '-Dforge.logging.console.level=info', - "-Dbasemetals.probe.phase=${phase.toLowerCase()}", - "-Dbasemetals.probe.expectedOrespawn=${stack.modVersion}", - "-Dbasemetals.probe.marker=${marker.absolutePath}", - '-jar', forge, 'nogui' - standardOutput = console - errorOutput = console - } - doLast { - new File(runDirectory, - "${stackName.toLowerCase()}-${phase.toLowerCase()}-console.txt") - .setText(console.toString('UTF-8'), 'UTF-8') - if (!marker.isFile()) { - throw new GradleException("${stack.display} ${phase} probe marker is missing") - } - Properties result = new Properties() - marker.withInputStream { result.load(it) } - if (result.getProperty('phase') != phase.toLowerCase() - || result.getProperty('registered') != 'true' - || result.getProperty('orespawn') != stack.modVersion) { - throw new GradleException("${stack.display} ${phase} probe result is invalid: ${result}") - } - File generatedOreConfig = stackName == 'Os3' - ? new File(runDirectory, 'config/orespawn3/basemetals.json') - : new File(runDirectory, 'config/basemetals-orespawn.json') - if (!generatedOreConfig.isFile()) { - throw new GradleException("${stack.display} did not materialize Base Metals ore data") - } - def generated = new JsonSlurper().parse(generatedOreConfig) - def generatedRules = stackName == 'Os3' ? generated.spawns : generated.ores - if (!(generatedRules instanceof Map) || generatedRules.size() != 11) { - throw new GradleException("${stack.display} loaded ${generatedRules?.size()} ore rules, expected 11") - } - String latestLog = new File(runDirectory, 'logs/latest.log').getText('UTF-8') - if (latestLog.contains('Fallback Ore Spawn Generator Enabled!') - || (stackName == 'Os3' - && !latestLog.contains('Loading Integration For basemetals')) - || (stackName == 'Os4' - && !latestLog.contains("worldgen provider 'basemetals' revision 1 is active"))) { - throw new GradleException("${stack.display} did not take exclusive ownership of Base Metals ore generation") - } - List failures = runtimeLogFailures(runDirectory) - if (!failures.isEmpty()) { - throw new GradleException("${stack.display} ${phase} logged runtime failures:\n" - + failures.take(20).join('\n')) - } - } - } - previous = processTask - } - tasks.register("packagedForge${stackName}RuntimeTest") { - group = 'verification' - description = "Creates and reloads a packaged Forge world with ${stack.display}." - dependsOn previous - } -} - -tasks.register('packagedForgeRuntimeTest') { - group = 'verification' - description = 'Runs fresh/reload packaged-server qualification with OreSpawn 3 and OreSpawn 4.' - dependsOn tasks.named('packagedForgeOs3RuntimeTest') - dependsOn tasks.named('packagedForgeOs4RuntimeTest') -} - -def mavenUploadUrl = providers.environmentVariable('MAVEN_UPLOAD_URL') - .orElse('https://invalid.invalid/missing-maven-upload-url') -def mavenUploadUsername = providers.environmentVariable('MAVEN_UPLOAD_USERNAME') -def mavenUploadPassword = providers.environmentVariable('MAVEN_UPLOAD_PASSWORD') - -publishing { - publications { - mavenJava(MavenPublication) { - groupId = project.group.toString() - artifactId = base.archivesName.get() - version = project.version.toString() - if (preparedReleaseDir.isPresent()) { - File prepared = file(preparedReleaseDir.get()) - artifact(new File(prepared, expectedReleaseFiles.get()[0])) - artifact(new File(prepared, expectedReleaseFiles.get()[1])) { classifier = 'sources' } - artifact(new File(prepared, expectedReleaseFiles.get()[2])) { classifier = 'javadoc' } - } else { - artifact(releaseJar) - artifact(tasks.named('sourcesJar')) - artifact(tasks.named('javadocJar')) - } - pom { - name = 'Base Metals' - description = 'Common metals, alloys, tools, armor, and world generation for Minecraft.' - url = 'https://github.com/MinecraftModDevelopmentMods/BaseMetals' - licenses { - license { - name = 'GNU Lesser General Public License, Version 2.1' - url = 'https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt' - } - } - scm { - connection = 'scm:git:https://github.com/MinecraftModDevelopmentMods/BaseMetals.git' - developerConnection = 'scm:git:ssh://git@github.com/MinecraftModDevelopmentMods/BaseMetals.git' - url = 'https://github.com/MinecraftModDevelopmentMods/BaseMetals' - } - } - } - } - repositories { - maven { - name = 'release' - url = uri(mavenUploadUrl.get()) - credentials { - username = mavenUploadUsername.orNull ?: '' - password = mavenUploadPassword.orNull ?: '' - } - } - } -} - -tasks.register('validateMavenReleaseCredentials') { - group = 'publishing' - doLast { - if (!providers.environmentVariable('MAVEN_UPLOAD_URL').isPresent() - || !mavenUploadUsername.isPresent() || !mavenUploadPassword.isPresent()) { - throw new GradleException('MAVEN_UPLOAD_URL, MAVEN_UPLOAD_USERNAME, and MAVEN_UPLOAD_PASSWORD are required') - } - if (providers.environmentVariable('MAVEN_UPLOAD_URL').get().startsWith('file:')) { - throw new GradleException('Maven release publication must use a remote repository') - } - } -} - -tasks.withType(PublishToMavenRepository).configureEach { - dependsOn tasks.named('validateMavenReleaseCredentials') - if (preparedReleaseDir.isPresent()) { - dependsOn tasks.named('verifyPreparedReleaseArtifacts') - } else { - dependsOn tasks.named('verifyReleaseArtifacts') - } -} - -idea { - module { - downloadSources = true - downloadJavadoc = true - } -} - -def eclipseXmlEscape = { String value -> - value.replace('&', '&') - .replace('"', '"') - .replace('<', '<') - .replace('>', '>') -} - -def eclipseArchiveLaunchEntry = { File archive -> - String memento = '' \ - + '' - ' ' -} - -def replaceBuildshipLaunchClasspath = { String contents, Collection archives -> - List lines = contents.replace('\r\n', '\n').split('\n', -1) as List - List buildshipLines = (0.. uniqueArchives = archives.collect { it.canonicalFile } - .unique { File archive -> archive.path.toLowerCase(Locale.ROOT) } - List missingArchives = uniqueArchives.findAll { !it.isFile() } - if (!missingArchives.isEmpty()) { - throw new GradleException("Eclipse launch archives are missing: ${missingArchives}") - } - lines[buildshipLines[0]] = uniqueArchives.collect(eclipseArchiveLaunchEntry).join('\n') - lines.join('\n') -} - -eclipse { - project { - buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder' - natures 'org.eclipse.buildship.core.gradleprojectnature' - } - classpath { - downloadSources = true - downloadJavadoc = true - file.withXml { provider -> - Node classpath = provider.asNode() - classpath.classpathentry.findAll { it.@kind == 'lib' }.each { - classpath.remove(it) - } - if (!classpath.classpathentry.any { - it.@kind == 'con' && it.@path == 'org.eclipse.buildship.core.gradleclasspathcontainer' - }) { - classpath.appendNode('classpathentry', [ - kind: 'con', path: 'org.eclipse.buildship.core.gradleclasspathcontainer' - ]) - } - } - } - synchronizationTasks 'genEclipseRuns' -} - -def configureEclipseBuildship = tasks.register('configureEclipseBuildship') { - group = 'ide' - description = 'Configures Buildship to use the wrapper and this invocation\'s Gradle cache.' - doLast { - File preferencesFile = file('.settings/org.eclipse.buildship.core.prefs') - Properties preferences = new Properties() - if (preferencesFile.isFile()) { - preferencesFile.withInputStream { preferences.load(it) } - } - Map required = [ - 'eclipse.preferences.version' : '1', - 'connection.gradle.distribution' : 'GRADLE_DISTRIBUTION(WRAPPER)', - 'connection.gradle.user.home' : gradle.gradleUserHomeDir.canonicalPath, - 'connection.project.dir' : '', - 'gradle.user.home' : gradle.gradleUserHomeDir.canonicalPath, - 'override.workspace.settings' : 'true' - ] - required.each { key, value -> preferences.setProperty(key, value) } - preferencesFile.parentFile.mkdirs() - preferencesFile.withOutputStream { - preferences.store(it, 'Generated by configureEclipseBuildship.') - } - } -} - -tasks.named('genEclipseRuns') { - finalizedBy configureEclipseBuildship, 'isolateEclipseProductionRuns' -} - -tasks.named('eclipse') { - dependsOn tasks.named('genEclipseRuns') -} - -tasks.register('isolateEclipseProductionRuns') { - group = 'ide' - description = 'Repairs Forge 1.12 launches and replaces compile-only Buildship entries with runtime jars.' - dependsOn sanitizedOrespawn3DevelopmentJar - doLast { - List runtimeArchives = configurations.runtimeClasspath.files as List - ['BaseMetals_Client.launch', 'BaseMetals_Server.launch'].each { name -> - File legacy = file(name) - if (legacy.isFile() && legacy.getText('UTF-8').contains('MAIN_TYPE" value="GradleStart')) { - if (!legacy.delete()) { - throw new GradleException("Could not retire obsolete ForgeGradle 2 launch ${name}") - } - } - } - ['runClient.launch', 'runServer.launch'].each { name -> - File launch = file(name) - if (!launch.isFile()) { - throw new GradleException("ForgeGradle did not generate ${name}") - } - String contents = launch.getText('UTF-8') - def programArguments = contents =~ /()/ - if (programArguments.count != 1) { - throw new GradleException("ForgeGradle generated malformed program arguments in ${name}") - } - String arguments = programArguments[0][2] - ['cache', 'metadata', 'to-srg', 'to-obf'].each { flag -> - String prefix = "--${flag} " - int valueStart = arguments.indexOf(prefix) - if (valueStart < 0) { - throw new GradleException("ForgeGradle omitted --${flag} from ${name}") - } - valueStart += prefix.length() - int valueEnd = arguments.indexOf(' --', valueStart) - if (valueEnd < 0) { - throw new GradleException("ForgeGradle generated an unterminated --${flag} path in ${name}") - } - String value = arguments.substring(valueStart, valueEnd) - if (!value.startsWith('"') || !value.endsWith('"')) { - arguments = "${arguments.substring(0, valueStart)}"${value}"${arguments.substring(valueEnd)}" - } - } - contents = contents.replace(programArguments[0][0], - programArguments[0][1] + arguments + programArguments[0][3]) - if (!contents.contains('org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE')) { - contents = contents.replace('', - ' ' - + System.lineSeparator() + '') - } - String eclipseModClasses = file('bin/main').absolutePath - if (contents.contains('key="MOD_CLASSES"')) { - contents = contents.replaceAll(//, - java.util.regex.Matcher.quoteReplacement( - "")) - } - contents = contents.replaceAll(//, - '') - contents = replaceBuildshipLaunchClasspath(contents, runtimeArchives) - launch.setText(contents.replace('\r\n', '\n'), 'UTF-8') - } - } -} - -tasks.register('verifyEclipseProductionClasspath') { - group = 'verification' - description = 'Verifies Java 8, launcher identity, path quoting, merged output, and test isolation.' - dependsOn tasks.named('genEclipseRuns') - doLast { - File prefs = file('.settings/org.eclipse.buildship.core.prefs') - if (!prefs.isFile()) { - throw new GradleException("Missing Eclipse Buildship configuration: ${prefs}") - } - Properties buildship = new Properties() - prefs.withInputStream { buildship.load(it) } - if (buildship.getProperty('connection.gradle.distribution') != 'GRADLE_DISTRIBUTION(WRAPPER)' - || file(buildship.getProperty('connection.gradle.user.home')).canonicalFile - != gradle.gradleUserHomeDir.canonicalFile) { - throw new GradleException('Buildship does not use the wrapper and selected Gradle cache') - } - String projectMetadata = file('.project').getText('UTF-8') - if (!projectMetadata.contains('org.eclipse.buildship.core.gradleprojectnature') - || !projectMetadata.contains('org.eclipse.buildship.core.gradleprojectbuilder')) { - throw new GradleException('Eclipse project metadata is missing Buildship integration') - } - String eclipseClasspath = file('.classpath').getText('UTF-8').replace('\\', '/') - if (!eclipseClasspath.contains('org.eclipse.buildship.core.gradleclasspathcontainer') - || eclipseClasspath.contains(']+path="[A-Za-z]:[\\\/].*/) { - throw new GradleException('Eclipse must expose dependencies through the Buildship container only') - } - List runtimeArchives = configurations.runtimeClasspath.files.collect { - it.canonicalFile - } - Set compileOnlyArchives = configurations.compileClasspath.files.collect { - it.canonicalFile - } as Set - compileOnlyArchives.removeAll(runtimeArchives) - ['runClient.launch', 'runServer.launch'].each { name -> - File launch = file(name) - String contents = launch.getText('UTF-8').replace('\\', '/') - List forbidden = [ - 'src/test', 'bin/test', 'build/classes/java/test', - 'junit-', 'mockito-', 'byte-buddy', 'objenesis' - ].findAll { contents.contains(it) } - if (!forbidden.isEmpty()) { - throw new GradleException("${name} exposes test code/dependencies: ${forbidden}") - } - if (!contents.contains('MAIN_TYPE" value="net.minecraftforge.launcher.Main"') - || !contents.contains('JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-8') - || !contents.contains('ATTR_EXCLUDE_TEST_CODE') - || contents.contains('org.eclipse.buildship.core.gradleclasspathcontainer') - || !contents.contains('PROJECT_ATTR" value="BaseMetals"') - || contents.contains('${MC_VERSION}') - || !contents.contains('MC_VERSION" value="1.12.2"')) { - throw new GradleException("${name} has the wrong launcher, JRE, classpath, project, or Minecraft version") - } - Set missingRuntime = runtimeArchives.findAll { - !contents.contains(it.canonicalPath.replace('\\', '/')) - } - Set leakedCompileOnly = compileOnlyArchives.findAll { - contents.contains(it.canonicalPath.replace('\\', '/')) - } - if (!missingRuntime.isEmpty() || !leakedCompileOnly.isEmpty()) { - throw new GradleException("${name} runtime isolation failed; missing=${missingRuntime}, " - + "compileOnly=${leakedCompileOnly}") - } - List runtimePositions = runtimeArchives.collect { - contents.indexOf(it.canonicalPath.replace('\\', '/')) - } - List sortedRuntimePositions = new ArrayList<>(runtimePositions) - sortedRuntimePositions.sort() - if (runtimePositions != sortedRuntimePositions) { - throw new GradleException("${name} does not preserve Gradle's order-sensitive runtime classpath") - } - if (!contents.contains("development-dependencies/OreSpawn-${project.orespawn3_version}-development.jar") - || contents.contains('renamer/renamed/mmd-orespawn-')) { - throw new GradleException("${name} does not use the signature-free remapped OreSpawn 3 dependency") - } - String expectedModClasses = file('bin/main').absolutePath.replace('\\', '/') - if (!contents.contains('MOD_CLASSES" value="' + expectedModClasses)) { - throw new GradleException("${name} does not use Eclipse's merged production output") - } - ['cache', 'metadata', 'to-srg', 'to-obf'].each { flag -> - if (!contents.contains("--${flag} "")) { - throw new GradleException("${name} does not quote its --${flag} path") - } - } - } - } -} - -tasks.register('prepareEclipse') { - group = 'ide' - description = 'Generates Forge launches and Eclipse metadata, then verifies production isolation.' - dependsOn tasks.named('eclipse') - dependsOn tasks.named('verifyEclipseProductionClasspath') -} - -tasks.named('verifyEclipseProductionClasspath') { - mustRunAfter tasks.named('eclipse') -} - -tasks.register('verifyWorkflowContracts') { - group = 'verification' - description = 'Validates pinned CI, tag, and multi-target release-dispatcher contracts.' - inputs.files(fileTree('.github/workflows') { include '*.yml' }) - doLast { - Map> required = [ - 'ci.yml': [ - 'master-1.12', 'feature/**', 'Cold Forge bootstrap', - 'Build, test, and audit', 'stage-legacy-dependencies.sh', - 'packagedForgeRuntimeTest', 'prepareEclipse', - 'Verify reproducible release archives' - ], - 'codeql-analysis.yml': [ - 'master-1.12', 'feature/**', 'github/codeql-action/init@', - 'stage-legacy-dependencies.sh', 'clean classes' - ], - 'validate-gradle-build.yml': [ - 'master-1.12', 'feature/**', 'gradle/actions/wrapper-validation@' - ], - 'release-on-tag.yml': [ - "tags:\n - '*.*.*.*'", 'Build, test, and audit', - 'deploy-release.yml', '**Nothing has been published.**' - ], - 'deploy-release.yml': [ - 'master-1.12)', 'master-1.18)', - 'stage-legacy-dependencies.sh', 'stage-orespawn-release.sh', - "mmdlib) curseforge_dependencies+=('261744(required)')", - 'confirm_live_publication' - ] - ] - required.each { name, fragments -> - File workflow = file(".github/workflows/${name}") - if (!workflow.isFile()) { - throw new GradleException("Missing workflow ${name}") - } - String text = workflow.getText('UTF-8').replace('\r\n', '\n') - List missing = fragments.findAll { !text.contains(it) } - if (!missing.isEmpty()) { - throw new GradleException("${name} is missing contract fragments ${missing}") - } - text.eachLine { line -> - def match = line =~ /^\s*uses:\s*([^\s#]+)(?:\s+#.*)?$/ - if (match.matches() && !(match.group(1) ==~ /[^@]+@[0-9a-f]{40}/)) { - throw new GradleException("${name} has an unpinned action: ${line.trim()}") - } - } - } - } -} - -tasks.named('check') { - dependsOn tasks.named('verifyWorkflowContracts') -} +ext.baseMetalsBuild = [ + mavenGroup : expectedMavenGroup, + mavenArtifact : expectedMavenArtifact, + mavenCoordinate : expectedMavenCoordinate, + archiveTextSuffixes: archiveTextSuffixes, + releaseJar : releaseJar +].asImmutable() + +// Keep the root build focused on compiling the mod. The applied scripts group +// release qualification, packaged runtime checks, publishing, and IDE support. +apply from: 'gradle/verification/support.gradle' +apply from: 'gradle/release/artifacts.gradle' +apply from: 'gradle/verification/packaged-forge.gradle' +apply from: 'gradle/release/publishing.gradle' +apply from: 'gradle/ide/eclipse.gradle' +apply from: 'gradle/verification/workflows.gradle' diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 00000000..274f79be --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,61 @@ +# Base Metals configuration + +With OreSpawn 4.1 or newer installed, Base Metals contributes one configuration +screen to OreSpawn's world-creation interface. Open **Create World → OreSpawn → +Mods**, then use the cog beside Base Metals. + +The screen edits the existing `config/BaseMetals.cfg` file. It does not create a +second configuration file. It exposes the existing 92 boolean settings plus +the restart-required `General/contentMode` selector under the five historical +categories: + +- General +- Base Metals +- Vanilla Bits +- Molten Fluids +- Forced Traits + +All settings affect registered content and require Minecraft to be restarted. +They do not alter pending settings in the current OreSpawn world-creation +session. Use OreSpawn's own editor for ore dimensions and distributions. + +Disabling one of the eleven materials whose ore is generated by OreSpawn shows +an additional confirmation with the matching `basemetals:legacy/*_ore` rule. +Disable that rule in OreSpawn before restarting; otherwise the provider still +refers to a block that Base Metals will no longer register. + +Done saves through Forge's normal Base Metals configuration event. Escape +discards edits on both category and root pages. Forge supplies the standard +Undo, Defaults, and restart-confirmation behavior. + +## Content modes + +- **High Fantasy** (`high_fantasy`) is the default and preserves the complete + historical Base Metals recipe, trade, loot, integration, and ore set. +- **Low Fantasy** (`low_fantasy`) keeps fantasy materials but removes equipment + and construction forms that do not fit the reviewed material policy. Base + Metals bows, crossbows, and fishing rods are unavailable in this mode. +- **Realism** (`realism`) applies the Low Fantasy restrictions and also removes + normal acquisition of Adamantine, Aquarium, Cold Iron, Mithril, and + Star-Steel. Their registered items and blocks remain available to load old + saves and can still be obtained deliberately through commands, creative mode, + or third-party data supplied by a pack. + +An older `BaseMetals.cfg` without `contentMode` is treated exactly like an +explicit `high_fantasy` configuration. Invalid values are corrected to High +Fantasy. The effective value is latched during startup, and a client whose +effective mode differs from the server is disconnected with an explanatory +Base Metals message before gameplay. + +Changing mode never rewrites an existing OreSpawn global override or saved +world profile. In particular, switching to Realism does not silently disable +fantasy rules in an existing world; review those rules in OreSpawn and disable +them manually when desired. Fresh Realism profiles default Adamantine, Cold +Iron, and Star-Steel generation off. + +## OreSpawn dependency + +Development, CI, and release qualification use the published OreSpawn +`4.1.0.112021` CurseForge artifact. Base Metals pins its exact CurseForge file +ID and SHA-256 and verifies the mod metadata and required client API classes +before accepting the dependency. diff --git a/docs/examples/basemetals-orespawn-disabled.json b/docs/examples/basemetals-orespawn-disabled.json new file mode 100644 index 00000000..8e0596ba --- /dev/null +++ b/docs/examples/basemetals-orespawn-disabled.json @@ -0,0 +1,489 @@ +{ + "schema_version": 5, + "provider_modid": "basemetals", + "provider_revision": 2, + "rocks": {}, + "ores": { + "basemetals:legacy/coldiron_ore": { + "enabled": false, + "block": "basemetals:coldiron_ore", + "native_generation": false, + "retrogen": false, + "outputs": [ + { + "block": "basemetals:coldiron_ore", + "weight": 100, + "min_y": -2048, + "max_y": 2048 + } + ], + "dimensions": { + "minecraft:the_nether": { + "enabled": true, + "min_y": 0, + "max_y": 127, + "frequency": 5.0, + "min_quantity": 4, + "max_quantity": 11, + "pattern": "default", + "height_distribution": "uniform", + "spread": 8, + "vertical_spread": 4, + "node_size": 8, + "host_blocks": [ + "minecraft:stone", + "minecraft:netherrack", + "minecraft:end_stone" + ], + "host_tags": [], + "host_families": [], + "biome_ids": [], + "excluded_biome_ids": [], + "biome_dictionary": [], + "excluded_biome_dictionary": [], + "geomes": {}, + "placement_channel": "orespawn:standard", + "discard_chance_on_air_exposure": 0.0 + } + } + }, + "basemetals:legacy/adamantine_ore": { + "enabled": false, + "block": "basemetals:adamantine_ore", + "native_generation": false, + "retrogen": false, + "outputs": [ + { + "block": "basemetals:adamantine_ore", + "weight": 100, + "min_y": -2048, + "max_y": 2048 + } + ], + "dimensions": { + "minecraft:the_nether": { + "enabled": true, + "min_y": 0, + "max_y": 127, + "frequency": 2.0, + "min_quantity": 4, + "max_quantity": 11, + "pattern": "default", + "height_distribution": "uniform", + "spread": 8, + "vertical_spread": 4, + "node_size": 8, + "host_blocks": [ + "minecraft:stone", + "minecraft:netherrack", + "minecraft:end_stone" + ], + "host_tags": [], + "host_families": [], + "biome_ids": [], + "excluded_biome_ids": [], + "biome_dictionary": [], + "excluded_biome_dictionary": [], + "geomes": {}, + "placement_channel": "orespawn:standard", + "discard_chance_on_air_exposure": 0.0 + } + } + }, + "basemetals:legacy/starsteel_ore": { + "enabled": false, + "block": "basemetals:starsteel_ore", + "native_generation": false, + "retrogen": false, + "outputs": [ + { + "block": "basemetals:starsteel_ore", + "weight": 100, + "min_y": -2048, + "max_y": 2048 + } + ], + "dimensions": { + "minecraft:the_end": { + "enabled": true, + "min_y": 0, + "max_y": 254, + "frequency": 5.0, + "min_quantity": 4, + "max_quantity": 11, + "pattern": "default", + "height_distribution": "uniform", + "spread": 8, + "vertical_spread": 4, + "node_size": 8, + "host_blocks": [ + "minecraft:stone", + "minecraft:netherrack", + "minecraft:end_stone" + ], + "host_tags": [], + "host_families": [], + "biome_ids": [], + "excluded_biome_ids": [], + "biome_dictionary": [], + "excluded_biome_dictionary": [], + "geomes": {}, + "placement_channel": "orespawn:standard", + "discard_chance_on_air_exposure": 0.0 + } + } + }, + "basemetals:legacy/copper_ore": { + "enabled": false, + "block": "basemetals:copper_ore", + "native_generation": false, + "retrogen": false, + "outputs": [ + { + "block": "basemetals:copper_ore", + "weight": 100, + "min_y": -2048, + "max_y": 2048 + } + ], + "dimension_selectors": { + "orespawn:all_except_nether_end": { + "enabled": true, + "min_y": 0, + "max_y": 95, + "frequency": 10.0, + "min_quantity": 4, + "max_quantity": 11, + "pattern": "default", + "height_distribution": "uniform", + "spread": 8, + "vertical_spread": 4, + "node_size": 8, + "host_blocks": [ + "minecraft:stone", + "minecraft:netherrack", + "minecraft:end_stone" + ], + "host_tags": [], + "host_families": [], + "biome_ids": [], + "excluded_biome_ids": [], + "biome_dictionary": [], + "excluded_biome_dictionary": [], + "geomes": {}, + "placement_channel": "orespawn:standard", + "discard_chance_on_air_exposure": 0.0 + } + } + }, + "basemetals:legacy/silver_ore": { + "enabled": false, + "block": "basemetals:silver_ore", + "native_generation": false, + "retrogen": false, + "outputs": [ + { + "block": "basemetals:silver_ore", + "weight": 100, + "min_y": -2048, + "max_y": 2048 + } + ], + "dimension_selectors": { + "orespawn:all_except_nether_end": { + "enabled": true, + "min_y": 0, + "max_y": 31, + "frequency": 4.0, + "min_quantity": 4, + "max_quantity": 11, + "pattern": "default", + "height_distribution": "uniform", + "spread": 8, + "vertical_spread": 4, + "node_size": 8, + "host_blocks": [ + "minecraft:stone", + "minecraft:netherrack", + "minecraft:end_stone" + ], + "host_tags": [], + "host_families": [], + "biome_ids": [], + "excluded_biome_ids": [], + "biome_dictionary": [], + "excluded_biome_dictionary": [], + "geomes": {}, + "placement_channel": "orespawn:standard", + "discard_chance_on_air_exposure": 0.0 + } + } + }, + "basemetals:legacy/tin_ore": { + "enabled": false, + "block": "basemetals:tin_ore", + "native_generation": false, + "retrogen": false, + "outputs": [ + { + "block": "basemetals:tin_ore", + "weight": 100, + "min_y": -2048, + "max_y": 2048 + } + ], + "dimension_selectors": { + "orespawn:all_except_nether_end": { + "enabled": true, + "min_y": 0, + "max_y": 127, + "frequency": 10.0, + "min_quantity": 4, + "max_quantity": 11, + "pattern": "default", + "height_distribution": "uniform", + "spread": 8, + "vertical_spread": 4, + "node_size": 8, + "host_blocks": [ + "minecraft:stone", + "minecraft:netherrack", + "minecraft:end_stone" + ], + "host_tags": [], + "host_families": [], + "biome_ids": [], + "excluded_biome_ids": [], + "biome_dictionary": [], + "excluded_biome_dictionary": [], + "geomes": {}, + "placement_channel": "orespawn:standard", + "discard_chance_on_air_exposure": 0.0 + } + } + }, + "basemetals:legacy/lead_ore": { + "enabled": false, + "block": "basemetals:lead_ore", + "native_generation": false, + "retrogen": false, + "outputs": [ + { + "block": "basemetals:lead_ore", + "weight": 100, + "min_y": -2048, + "max_y": 2048 + } + ], + "dimension_selectors": { + "orespawn:all_except_nether_end": { + "enabled": true, + "min_y": 0, + "max_y": 63, + "frequency": 5.0, + "min_quantity": 4, + "max_quantity": 11, + "pattern": "default", + "height_distribution": "uniform", + "spread": 8, + "vertical_spread": 4, + "node_size": 8, + "host_blocks": [ + "minecraft:stone", + "minecraft:netherrack", + "minecraft:end_stone" + ], + "host_tags": [], + "host_families": [], + "biome_ids": [], + "excluded_biome_ids": [], + "biome_dictionary": [], + "excluded_biome_dictionary": [], + "geomes": {}, + "placement_channel": "orespawn:standard", + "discard_chance_on_air_exposure": 0.0 + } + } + }, + "basemetals:legacy/zinc_ore": { + "enabled": false, + "block": "basemetals:zinc_ore", + "native_generation": false, + "retrogen": false, + "outputs": [ + { + "block": "basemetals:zinc_ore", + "weight": 100, + "min_y": -2048, + "max_y": 2048 + } + ], + "dimension_selectors": { + "orespawn:all_except_nether_end": { + "enabled": true, + "min_y": 0, + "max_y": 95, + "frequency": 5.0, + "min_quantity": 4, + "max_quantity": 11, + "pattern": "default", + "height_distribution": "uniform", + "spread": 8, + "vertical_spread": 4, + "node_size": 8, + "host_blocks": [ + "minecraft:stone", + "minecraft:netherrack", + "minecraft:end_stone" + ], + "host_tags": [], + "host_families": [], + "biome_ids": [], + "excluded_biome_ids": [], + "biome_dictionary": [], + "excluded_biome_dictionary": [], + "geomes": {}, + "placement_channel": "orespawn:standard", + "discard_chance_on_air_exposure": 0.0 + } + } + }, + "basemetals:legacy/mercury_ore": { + "enabled": false, + "block": "basemetals:mercury_ore", + "native_generation": false, + "retrogen": false, + "outputs": [ + { + "block": "basemetals:mercury_ore", + "weight": 100, + "min_y": -2048, + "max_y": 2048 + } + ], + "dimension_selectors": { + "orespawn:all_except_nether_end": { + "enabled": true, + "min_y": 0, + "max_y": 31, + "frequency": 3.0, + "min_quantity": 4, + "max_quantity": 11, + "pattern": "default", + "height_distribution": "uniform", + "spread": 8, + "vertical_spread": 4, + "node_size": 8, + "host_blocks": [ + "minecraft:stone", + "minecraft:netherrack", + "minecraft:end_stone" + ], + "host_tags": [], + "host_families": [], + "biome_ids": [], + "excluded_biome_ids": [], + "biome_dictionary": [], + "excluded_biome_dictionary": [], + "geomes": {}, + "placement_channel": "orespawn:standard", + "discard_chance_on_air_exposure": 0.0 + } + } + }, + "basemetals:legacy/nickel_ore": { + "enabled": false, + "block": "basemetals:nickel_ore", + "native_generation": false, + "retrogen": false, + "outputs": [ + { + "block": "basemetals:nickel_ore", + "weight": 100, + "min_y": -2048, + "max_y": 2048 + } + ], + "dimension_selectors": { + "orespawn:all_except_nether_end": { + "enabled": true, + "min_y": 32, + "max_y": 95, + "frequency": 1.0, + "min_quantity": 4, + "max_quantity": 11, + "pattern": "default", + "height_distribution": "uniform", + "spread": 8, + "vertical_spread": 4, + "node_size": 8, + "host_blocks": [ + "minecraft:stone", + "minecraft:netherrack", + "minecraft:end_stone" + ], + "host_tags": [], + "host_families": [], + "biome_ids": [], + "excluded_biome_ids": [], + "biome_dictionary": [], + "excluded_biome_dictionary": [], + "geomes": {}, + "placement_channel": "orespawn:standard", + "discard_chance_on_air_exposure": 0.0 + } + } + }, + "basemetals:legacy/platinum_ore": { + "enabled": false, + "block": "basemetals:platinum_ore", + "native_generation": false, + "retrogen": false, + "outputs": [ + { + "block": "basemetals:platinum_ore", + "weight": 100, + "min_y": -2048, + "max_y": 2048 + } + ], + "dimension_selectors": { + "orespawn:all_except_nether_end": { + "enabled": true, + "min_y": 1, + "max_y": 31, + "frequency": 0.125, + "min_quantity": 4, + "max_quantity": 11, + "pattern": "default", + "height_distribution": "uniform", + "spread": 8, + "vertical_spread": 4, + "node_size": 8, + "host_blocks": [ + "minecraft:stone", + "minecraft:netherrack", + "minecraft:end_stone" + ], + "host_tags": [], + "host_families": [], + "biome_ids": [], + "excluded_biome_ids": [], + "biome_dictionary": [], + "excluded_biome_dictionary": [], + "geomes": {}, + "placement_channel": "orespawn:standard", + "discard_chance_on_air_exposure": 0.0 + } + } + } + }, + "fluid_deposits": {}, + "geomes": {}, + "biome_rules": {}, + "terrain_dimensions": {}, + "biome_palettes": {}, + "dimension_materials": {}, + "templates": {}, + "merge_new_entries_into_existing_worlds": true +} diff --git a/docs/world-generation.md b/docs/world-generation.md new file mode 100644 index 00000000..47781f14 --- /dev/null +++ b/docs/world-generation.md @@ -0,0 +1,56 @@ +# Base Metals world generation + +Base Metals 2.6.0 requires OreSpawn 4.1.0.112021 or newer in the 4.x line. +OreSpawn is the only Base Metals ore generator. Base Metals does not register a +fallback generator. + +Base Metals submits a schema-5 API provider at revision 2 containing eleven +stable rules. Cold iron and Adamantine generate +in the Nether, Star-Steel generates in the End, and copper, silver, tin, lead, +zinc, mercury, nickel and platinum generate in ordinary dimensions. Existing +registry names and the historical distribution values are preserved. + +High Fantasy and Low Fantasy enable all eleven rules by default. A fresh +Realism profile defaults Adamantine, Cold Iron, and Star-Steel off. Existing +global overrides and saved-world profiles remain authoritative when the mode +changes and are never rewritten silently. + +## Letting another mod generate the ores + +For a new world, copy +[`examples/basemetals-orespawn-disabled.json`](examples/basemetals-orespawn-disabled.json) +to the instance's `config` directory and rename it to: + +```text +basemetals-orespawn.json +``` + +The example is a complete OreSpawn provider override with every Base Metals +ore rule disabled. Configure CoFH World or another generator separately, then +create the world. OreSpawn will still be present because it is a required +dependency, but it will not place Base Metals ores. + +OreSpawn stores a self-contained configuration snapshot for each world. To +change an existing world, disable the Base Metals rules through OreSpawn's +configuration screen or edit: + +```text +/serverconfig/orespawn-worldgen.json +``` + +Make a backup before editing a world's snapshot. Changing generation settings +does not remove ore from chunks that have already been generated. Retrogen is +disabled by default and should remain disabled when another generator owns the +same ores. + +## Upgrading an older installation + +OreSpawn 4 migrates `config/orespawn3/basemetals.json` into the same stable +rule IDs used by the native provider. Customized frequencies, heights and +disabled rules therefore remain associated with their Base Metals rules. +Previously generated `config/basemetals-orespawn.json` overrides also remain +valid and authoritative. + +The legacy MMDLib settings named `using_orespawn` and `fallback_orespawn` are +not Base Metals OreSpawn 4 controls. Use the provider override or the per-world +OreSpawn configuration instead. diff --git a/gradle.properties b/gradle.properties index ad9340df..619cba34 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ org.gradle.parallel=false net.minecraftforge.gradle.merge-source-sets=false mod_group=zone.moddev.mc.basemetals -mod_version=2.5.1.112021 +mod_version=2.6.0.112021 # Generic release-dispatcher metadata. minecraft_version=1.12.2 @@ -30,16 +30,17 @@ mmdlib_curse_file_id=2712947 mmdlib_version=1.0.0-rc2.36 mmdlib_sha256=FE2229E6755A5FD306C33CC22DCCF055378D371339133E4912C5DC9213E360AF +orespawn4_curse_project_id=245586 +orespawn4_curse_file_id=9008120 +orespawn4_version=4.1.0.112021 +orespawn4_sha256=B3018214BD1A612309A78DF02C552C0948A8FCD3CF314F25D40071E8B4605670 + +# Rejection and migration fixture only; Base Metals no longer supports OS3. orespawn3_curse_project_id=245586 orespawn3_curse_file_id=2913786 orespawn3_version=3.3.1.179 orespawn3_sha256=86A5E567950D5428F413A0C744FD4EA6DF5807955CBD444392595A1871CC1DFA -orespawn4_curse_project_id=245586 -orespawn4_curse_file_id=8843769 -orespawn4_version=4.0.17.112021 -orespawn4_sha256=DA99AC45B663E0FB582AC175E7D5AC53C962BD03F00E79299C4BE0E33E9DCCF2 - alt_curse_project_id=243157 alt_curse_file_id=2691613 alt_version=2.0.3.45 @@ -55,6 +56,11 @@ tconstruct_curse_file_id=2571785 tconstruct_version=2.10.1.87 tconstruct_sha256=B1E21352C7BCEC95E33769308D9E70CC83E8F3A97C27FB94F4F0F55CE3CF96F2 +taiga_curse_project_id=247661 +taiga_curse_file_id=2626416 +taiga_version=1.12.2-1.3.4 +taiga_sha256=FFD53989E9953D6B90AE075D2E5F0F99FFBDF54D067EBACA8207AF8A908FD46C + conarm_curse_project_id=287683 conarm_curse_file_id=2622725 conarm_version=1.1.2 @@ -75,6 +81,26 @@ cofhcore_curse_file_id=2920433 cofhcore_version=4.6.6.1 cofhcore_sha256=E07B0C48DEF9CE8CFAA4CF7A7C656BF7F7D6815F74FBCC2957DD43EFA78486A9 +cofhworld_curse_project_id=271384 +cofhworld_curse_file_id=2920434 +cofhworld_version=1.4.0.1 +cofhworld_sha256=F10CD57075690ECBE52094F8AF0D2A5AF12F89C82B7C6EB73D3D090D74206EA0 + +redstoneflux_curse_project_id=270789 +redstoneflux_curse_file_id=2920436 +redstoneflux_version=2.1.1.1 +redstoneflux_sha256=6FF7F96D076BFAAD83FB6BA92EC457B8A76391439663B0CC32A9EC5398345280 + +ancientwarfare_curse_project_id=224602 +ancientwarfare_curse_file_id=3293318 +ancientwarfare_version=1.12.2-2.7.0.1038 +ancientwarfare_sha256=8D1A080C33537BBE8B9585FE67A0B52EFA8879C4210972082DD52995D9DE90CA + +codechickenlib_curse_project_id=242818 +codechickenlib_curse_file_id=2779848 +codechickenlib_version=3.2.3.358 +codechickenlib_sha256=5F8499F7EE2590E45110BBF296B2BF101AEC15897E28D5E9759CF8F2387D8A74 + legacy_basemetals_curse_project_id=240967 legacy_basemetals_curse_file_id=2712965 legacy_basemetals_version=2.5.0-rc2.332 diff --git a/gradle/README.md b/gradle/README.md new file mode 100644 index 00000000..c06a1502 --- /dev/null +++ b/gradle/README.md @@ -0,0 +1,33 @@ +# Base Metals build scripts + +The root `build.gradle` contains the parts needed to compile and package Base +Metals: project identity, Java and Forge setup, development runs, resource +processing, and archive creation. + +The supporting scripts keep the less frequently changed release machinery out +of that main path: + +- `dependencies.gradle` owns exact third-party coordinates and the matching + development, fixture, and verification configurations. +- `verification/support.gradle` defines shared toolchain, dependency, JSON, + and OreSpawn provider checks. +- `verification/packaged-forge.gradle` prepares the common clean Forge runtime + and its reusable probes. +- `verification/packaged-forge-dependencies.gradle` checks required OreSpawn + behavior and preservation of an existing override. +- `verification/packaged-forge-migration.gradle` covers OreSpawn 3 migration. +- `verification/packaged-forge-cofh.gradle` covers the optional CoFH World + coexistence profile. +- `verification/packaged-forge-tinkers.gradle` covers Tinkers, TAIGA, + Construct's Armory, and content-mode combinations. +- `release/artifacts.gradle` audits release jars and writes checksums. +- `release/publishing.gradle` defines guarded Maven publication. +- `ide/eclipse.gradle` generates and verifies isolated Eclipse launches. +- `verification/workflows.gradle` checks the pinned GitHub Actions contracts. + +Shared values are exposed through small immutable maps. This lets an applied +script state which part of the build contract it uses instead of depending on +variables that happen to exist in another script's scope. + +When adding a task, put it beside the workflow it supports. Keep task names +stable because CI and the release dispatcher call them directly. diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle new file mode 100644 index 00000000..8d02a3b2 --- /dev/null +++ b/gradle/dependencies.gradle @@ -0,0 +1,138 @@ +// Dependency coordinates live together so development and release checks use the same files. +def curseCoordinate = { String slug, String projectId, String fileId -> + "curse.maven:${slug}-${projectId}:${fileId}".toString() +} + +def dependencySpecs = [ + mmdlib: [ + coordinate: curseCoordinate('mmdlib', project.mmdlib_curse_project_id, project.mmdlib_curse_file_id), + version: project.mmdlib_version, sha256: project.mmdlib_sha256, required: true + ], + orespawn4: [ + coordinate: curseCoordinate('mmd-orespawn', project.orespawn4_curse_project_id, + project.orespawn4_curse_file_id), + version: project.orespawn4_version, sha256: project.orespawn4_sha256, required: true + ], + orespawn3: [ + coordinate: curseCoordinate('mmd-orespawn', project.orespawn3_curse_project_id, project.orespawn3_curse_file_id), + version: project.orespawn3_version, sha256: project.orespawn3_sha256, required: false + ], + alt: [ + coordinate: curseCoordinate('additional-loot-tables', project.alt_curse_project_id, project.alt_curse_file_id), + version: project.alt_version, sha256: project.alt_sha256, required: false + ], + mantle: [ + coordinate: curseCoordinate('mantle', project.mantle_curse_project_id, project.mantle_curse_file_id), + version: project.mantle_version, sha256: project.mantle_sha256, required: false + ], + tconstruct: [ + coordinate: curseCoordinate('tinkers-construct', project.tconstruct_curse_project_id, project.tconstruct_curse_file_id), + version: project.tconstruct_version, sha256: project.tconstruct_sha256, required: false + ], + taiga: [ + coordinate: curseCoordinate('taiga-tinkers-alloying-addon', project.taiga_curse_project_id, + project.taiga_curse_file_id), + version: project.taiga_version, sha256: project.taiga_sha256, required: false + ], + conarm: [ + coordinate: curseCoordinate('constructs-armory', project.conarm_curse_project_id, project.conarm_curse_file_id), + version: project.conarm_version, sha256: project.conarm_sha256, required: false + ], + thaumcraft: [ + coordinate: curseCoordinate('thaumcraft', project.thaumcraft_curse_project_id, project.thaumcraft_curse_file_id), + version: project.thaumcraft_version, sha256: project.thaumcraft_sha256, required: false + ], + baubles: [ + coordinate: curseCoordinate('baubles', project.baubles_curse_project_id, project.baubles_curse_file_id), + version: project.baubles_version, sha256: project.baubles_sha256, required: false + ], + cofhcore: [ + coordinate: curseCoordinate('cofh-core', project.cofhcore_curse_project_id, project.cofhcore_curse_file_id), + version: project.cofhcore_version, sha256: project.cofhcore_sha256, required: false + ], + cofhworld: [ + coordinate: curseCoordinate('cofh-world', project.cofhworld_curse_project_id, + project.cofhworld_curse_file_id), + version: project.cofhworld_version, sha256: project.cofhworld_sha256, required: false + ], + redstoneflux: [ + coordinate: curseCoordinate('redstone-flux', project.redstoneflux_curse_project_id, + project.redstoneflux_curse_file_id), + version: project.redstoneflux_version, sha256: project.redstoneflux_sha256, required: false + ], + ancientwarfare: [ + coordinate: curseCoordinate('ancient-warfare-2', project.ancientwarfare_curse_project_id, + project.ancientwarfare_curse_file_id), + version: project.ancientwarfare_version, sha256: project.ancientwarfare_sha256, required: false + ], + codechickenlib: [ + coordinate: curseCoordinate('codechicken-lib-1-8', project.codechickenlib_curse_project_id, + project.codechickenlib_curse_file_id), + version: project.codechickenlib_version, sha256: project.codechickenlib_sha256, required: false + ] +] + +configurations { + legacyDependencyArtifacts { + canBeConsumed = false + canBeResolved = true + transitive = false + } + orespawn3FixtureArtifact { + canBeConsumed = false + canBeResolved = true + transitive = false + } + legacyBaselineArtifact { + canBeConsumed = false + canBeResolved = true + transitive = false + } +} + +def mmdlibDevelopmentDependency = renamer.dependency(dependencySpecs.mmdlib.coordinate) +def orespawn4DevelopmentDependency = renamer.dependency(dependencySpecs.orespawn4.coordinate) +def mantleDevelopmentDependency = renamer.dependency(dependencySpecs.mantle.coordinate) +def tconstructDevelopmentDependency = renamer.dependency(dependencySpecs.tconstruct.coordinate) + +dependencies { + implementation minecraft.dependency( + "net.minecraftforge:forge:${project.minecraft_version}-${project.forge_version}") + compileOnly 'org.lwjgl.lwjgl:lwjgl_util:2.9.4-nightly-20150209' + + implementation mmdlibDevelopmentDependency + compileOnly orespawn4DevelopmentDependency + runtimeOnly orespawn4DevelopmentDependency + + compileOnly renamer.dependency(dependencySpecs.alt.coordinate) + compileOnly mantleDevelopmentDependency + compileOnly tconstructDevelopmentDependency + compileOnly renamer.dependency(dependencySpecs.conarm.coordinate) + compileOnly renamer.dependency(dependencySpecs.thaumcraft.coordinate) + compileOnly renamer.dependency(dependencySpecs.baubles.coordinate) + compileOnly renamer.dependency(dependencySpecs.cofhcore.coordinate) + + testCompileOnly mantleDevelopmentDependency + testCompileOnly tconstructDevelopmentDependency + testCompileOnly orespawn4DevelopmentDependency + + dependencySpecs.each { name, spec -> + if (name != 'orespawn3') { + legacyDependencyArtifacts spec.coordinate + } + } + orespawn3FixtureArtifact dependencySpecs.orespawn3.coordinate + legacyBaselineArtifact curseCoordinate('base-metals', + project.legacy_basemetals_curse_project_id, + project.legacy_basemetals_curse_file_id) + + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.2' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.10.2' + testImplementation 'org.mockito:mockito-core:2.28.2' +} + +ext.baseMetalsDependencies = [ + specs : dependencySpecs, + curseCoordinate: curseCoordinate +].asImmutable() diff --git a/gradle/ide/eclipse.gradle b/gradle/ide/eclipse.gradle new file mode 100644 index 00000000..123e294b --- /dev/null +++ b/gradle/ide/eclipse.gradle @@ -0,0 +1,260 @@ +// Eclipse support repairs ForgeGradle's generated launches without changing product dependencies. +idea { + module { + downloadSources = true + downloadJavadoc = true + } +} + +def eclipseXmlEscape = { String value -> + value.replace('&', '&') + .replace('"', '"') + .replace('<', '<') + .replace('>', '>') +} + +def eclipseArchiveLaunchEntry = { File archive -> + String memento = '' \ + + '' + ' ' +} + +def replaceBuildshipLaunchClasspath = { String contents, Collection archives -> + List lines = contents.replace('\r\n', '\n').split('\n', -1) as List + List buildshipLines = (0.. uniqueArchives = archives.collect { it.canonicalFile } + .unique { File archive -> archive.path.toLowerCase(Locale.ROOT) } + List missingArchives = uniqueArchives.findAll { !it.isFile() } + if (!missingArchives.isEmpty()) { + throw new GradleException("Eclipse launch archives are missing: ${missingArchives}") + } + lines[buildshipLines[0]] = uniqueArchives.collect(eclipseArchiveLaunchEntry).join('\n') + lines.join('\n') +} + +eclipse { + project { + buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder' + natures 'org.eclipse.buildship.core.gradleprojectnature' + } + classpath { + downloadSources = true + downloadJavadoc = true + file.withXml { provider -> + Node classpath = provider.asNode() + classpath.classpathentry.findAll { it.@kind == 'lib' }.each { + classpath.remove(it) + } + if (!classpath.classpathentry.any { + it.@kind == 'con' && it.@path == 'org.eclipse.buildship.core.gradleclasspathcontainer' + }) { + classpath.appendNode('classpathentry', [ + kind: 'con', path: 'org.eclipse.buildship.core.gradleclasspathcontainer' + ]) + } + } + } + synchronizationTasks 'genEclipseRuns' +} + +def configureEclipseBuildship = tasks.register('configureEclipseBuildship') { + group = 'ide' + description = 'Configures Buildship to use the wrapper and this invocation\'s Gradle cache.' + doLast { + File preferencesFile = file('.settings/org.eclipse.buildship.core.prefs') + Properties preferences = new Properties() + if (preferencesFile.isFile()) { + preferencesFile.withInputStream { preferences.load(it) } + } + Map required = [ + 'eclipse.preferences.version' : '1', + 'connection.gradle.distribution' : 'GRADLE_DISTRIBUTION(WRAPPER)', + 'connection.gradle.user.home' : gradle.gradleUserHomeDir.canonicalPath, + 'connection.project.dir' : '', + 'gradle.user.home' : gradle.gradleUserHomeDir.canonicalPath, + 'override.workspace.settings' : 'true' + ] + required.each { key, value -> preferences.setProperty(key, value) } + preferencesFile.parentFile.mkdirs() + preferencesFile.withOutputStream { + preferences.store(it, 'Generated by configureEclipseBuildship.') + } + } +} + +tasks.named('genEclipseRuns') { + finalizedBy configureEclipseBuildship, 'isolateEclipseProductionRuns' +} + +tasks.named('eclipse') { + dependsOn tasks.named('genEclipseRuns') +} + +tasks.register('isolateEclipseProductionRuns') { + group = 'ide' + description = 'Repairs Forge 1.12 launches and replaces compile-only Buildship entries with runtime jars.' + doLast { + List runtimeArchives = configurations.runtimeClasspath.files as List + ['BaseMetals_Client.launch', 'BaseMetals_Server.launch'].each { name -> + File legacy = file(name) + if (legacy.isFile() && legacy.getText('UTF-8').contains('MAIN_TYPE" value="GradleStart')) { + if (!legacy.delete()) { + throw new GradleException("Could not retire obsolete ForgeGradle 2 launch ${name}") + } + } + } + ['runClient.launch', 'runServer.launch'].each { name -> + File launch = file(name) + if (!launch.isFile()) { + throw new GradleException("ForgeGradle did not generate ${name}") + } + String contents = launch.getText('UTF-8') + def programArguments = contents =~ /()/ + if (programArguments.count != 1) { + throw new GradleException("ForgeGradle generated malformed program arguments in ${name}") + } + String arguments = programArguments[0][2] + ['cache', 'metadata', 'to-srg', 'to-obf'].each { flag -> + String prefix = "--${flag} " + int valueStart = arguments.indexOf(prefix) + if (valueStart < 0) { + throw new GradleException("ForgeGradle omitted --${flag} from ${name}") + } + valueStart += prefix.length() + int valueEnd = arguments.indexOf(' --', valueStart) + if (valueEnd < 0) { + throw new GradleException("ForgeGradle generated an unterminated --${flag} path in ${name}") + } + String value = arguments.substring(valueStart, valueEnd) + if (!value.startsWith('"') || !value.endsWith('"')) { + arguments = "${arguments.substring(0, valueStart)}"${value}"${arguments.substring(valueEnd)}" + } + } + contents = contents.replace(programArguments[0][0], + programArguments[0][1] + arguments + programArguments[0][3]) + if (!contents.contains('org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE')) { + contents = contents.replace('', + ' ' + + System.lineSeparator() + '') + } + String eclipseModClasses = file('bin/main').absolutePath + if (contents.contains('key="MOD_CLASSES"')) { + contents = contents.replaceAll(//, + java.util.regex.Matcher.quoteReplacement( + "")) + } + contents = contents.replaceAll(//, + '') + contents = replaceBuildshipLaunchClasspath(contents, runtimeArchives) + launch.setText(contents.replace('\r\n', '\n'), 'UTF-8') + } + } +} + +tasks.register('verifyEclipseProductionClasspath') { + group = 'verification' + description = 'Verifies Java 8, launcher identity, path quoting, merged output, and test isolation.' + dependsOn tasks.named('genEclipseRuns') + doLast { + File prefs = file('.settings/org.eclipse.buildship.core.prefs') + if (!prefs.isFile()) { + throw new GradleException("Missing Eclipse Buildship configuration: ${prefs}") + } + Properties buildship = new Properties() + prefs.withInputStream { buildship.load(it) } + if (buildship.getProperty('connection.gradle.distribution') != 'GRADLE_DISTRIBUTION(WRAPPER)' + || file(buildship.getProperty('connection.gradle.user.home')).canonicalFile + != gradle.gradleUserHomeDir.canonicalFile) { + throw new GradleException('Buildship does not use the wrapper and selected Gradle cache') + } + String projectMetadata = file('.project').getText('UTF-8') + if (!projectMetadata.contains('org.eclipse.buildship.core.gradleprojectnature') + || !projectMetadata.contains('org.eclipse.buildship.core.gradleprojectbuilder')) { + throw new GradleException('Eclipse project metadata is missing Buildship integration') + } + String eclipseClasspath = file('.classpath').getText('UTF-8').replace('\\', '/') + if (!eclipseClasspath.contains('org.eclipse.buildship.core.gradleclasspathcontainer') + || eclipseClasspath.contains(']+path="[A-Za-z]:[\\\/].*/) { + throw new GradleException('Eclipse must expose dependencies through the Buildship container only') + } + List runtimeArchives = configurations.runtimeClasspath.files.collect { + it.canonicalFile + } + Set compileOnlyArchives = configurations.compileClasspath.files.collect { + it.canonicalFile + } as Set + compileOnlyArchives.removeAll(runtimeArchives) + ['runClient.launch', 'runServer.launch'].each { name -> + File launch = file(name) + String contents = launch.getText('UTF-8').replace('\\', '/') + List forbidden = [ + 'src/test', 'bin/test', 'build/classes/java/test', + 'junit-', 'mockito-', 'byte-buddy', 'objenesis' + ].findAll { contents.contains(it) } + if (!forbidden.isEmpty()) { + throw new GradleException("${name} exposes test code/dependencies: ${forbidden}") + } + if (!contents.contains('MAIN_TYPE" value="net.minecraftforge.launcher.Main"') + || !contents.contains('JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-8') + || !contents.contains('ATTR_EXCLUDE_TEST_CODE') + || contents.contains('org.eclipse.buildship.core.gradleclasspathcontainer') + || !contents.contains('PROJECT_ATTR" value="BaseMetals"') + || contents.contains('${MC_VERSION}') + || !contents.contains('MC_VERSION" value="1.12.2"')) { + throw new GradleException("${name} has the wrong launcher, JRE, classpath, project, or Minecraft version") + } + Set missingRuntime = runtimeArchives.findAll { + !contents.contains(it.canonicalPath.replace('\\', '/')) + } + Set leakedCompileOnly = compileOnlyArchives.findAll { + contents.contains(it.canonicalPath.replace('\\', '/')) + } + if (!missingRuntime.isEmpty() || !leakedCompileOnly.isEmpty()) { + throw new GradleException("${name} runtime isolation failed; missing=${missingRuntime}, " + + "compileOnly=${leakedCompileOnly}") + } + List runtimePositions = runtimeArchives.collect { + contents.indexOf(it.canonicalPath.replace('\\', '/')) + } + List sortedRuntimePositions = new ArrayList<>(runtimePositions) + sortedRuntimePositions.sort() + if (runtimePositions != sortedRuntimePositions) { + throw new GradleException("${name} does not preserve Gradle's order-sensitive runtime classpath") + } + String expectedOreSpawnName = "mmd-orespawn-${project.orespawn4_curse_project_id}-${project.orespawn4_curse_file_id}-renamed.jar" + List oreSpawnRuntime = runtimeArchives.findAll { it.name == expectedOreSpawnName } + if (oreSpawnRuntime.size() != 1 + || !contents.contains(oreSpawnRuntime.first().canonicalPath.replace('\\', '/')) + || contents.contains(project.orespawn3_version.toString())) { + throw new GradleException("${name} does not use only the remapped OreSpawn 4 dependency") + } + String expectedModClasses = file('bin/main').absolutePath.replace('\\', '/') + if (!contents.contains('MOD_CLASSES" value="' + expectedModClasses)) { + throw new GradleException("${name} does not use Eclipse's merged production output") + } + ['cache', 'metadata', 'to-srg', 'to-obf'].each { flag -> + if (!contents.contains("--${flag} "")) { + throw new GradleException("${name} does not quote its --${flag} path") + } + } + } + } +} + +tasks.register('prepareEclipse') { + group = 'ide' + description = 'Generates Forge launches and Eclipse metadata, then verifies production isolation.' + dependsOn tasks.named('eclipse') + dependsOn tasks.named('verifyEclipseProductionClasspath') +} + +tasks.named('verifyEclipseProductionClasspath') { + mustRunAfter tasks.named('eclipse') +} diff --git a/gradle/release/artifacts.gradle b/gradle/release/artifacts.gradle new file mode 100644 index 00000000..d20941bd --- /dev/null +++ b/gradle/release/artifacts.gradle @@ -0,0 +1,236 @@ +import groovy.json.JsonSlurper +import java.nio.charset.StandardCharsets +import java.util.jar.Manifest +import java.util.zip.ZipFile + +def buildContract = project.ext.baseMetalsBuild +def verification = project.ext.baseMetalsVerification +def expectedMavenCoordinate = buildContract.mavenCoordinate +def archiveTextSuffixes = buildContract.archiveTextSuffixes +def expectedReleaseFiles = verification.expectedReleaseFiles +def preparedReleaseDir = verification.preparedReleaseDir +def sha256 = verification.sha256 + +// These tasks inspect the files that would actually be published. +tasks.register('verifyReleaseArtifacts') { + group = 'verification' + description = 'Audits deterministic jars, legacy inventory, bytecode, metadata, and package isolation.' + dependsOn tasks.named('assemble') + dependsOn tasks.named('verifyReleaseDependencies') + doLast { + File libs = layout.buildDirectory.dir('libs').get().asFile + List expected = expectedReleaseFiles.get().sort() + List jars = (libs.listFiles() ?: [] as File[]) + .findAll { it.name.endsWith('.jar') } + .sort { it.name } + if (jars.collect { it.name } != expected || jars.any { it.length() == 0L }) { + throw new GradleException("Release directory must contain exactly ${expected}; found ${jars*.name}") + } + + File mainJar = new File(libs, "BaseMetals-${project.version}.jar") + ZipFile zip = new ZipFile(mainJar) + try { + List names = zip.entries().collect { it.name } + List forbiddenNames = names.findAll { name -> + name.startsWith('com/mcmoddev/lib/') + || name.startsWith('net/minecraft/') + || name.startsWith('net/minecraftforge/') + || name.startsWith('org/junit/') + || name.contains('/test/') + || name.toLowerCase().contains('fixture') + || name.toLowerCase().contains('agent') + || name.toLowerCase().contains('runtimeprobe') + } + if (!forbiddenNames.isEmpty()) { + throw new GradleException("Release jar contains forbidden entries: ${forbiddenNames.take(20)}") + } + + zip.entries().findAll { it.name.endsWith('.class') }.each { entry -> + byte[] header = new byte[8] + zip.getInputStream(entry).withCloseable { input -> + if (input.read(header) != header.length) { + throw new GradleException("Cannot inspect bytecode header for ${entry.name}") + } + } + int major = ((header[6] & 0xff) << 8) | (header[7] & 0xff) + if (major != 52) { + throw new GradleException("${entry.name} uses Java class major ${major}, expected 52") + } + } + + def manifestEntry = zip.getEntry('META-INF/MANIFEST.MF') + def manifest = manifestEntry == null ? null + : new Manifest(zip.getInputStream(manifestEntry)).mainAttributes + if (manifest == null + || manifest.getValue('Maven-Artifact') != expectedMavenCoordinate + || manifest.getValue('Implementation-Version') != project.mod_version + || manifest.getValue('Timestamp') != null + || manifest.getValue('Built-On') != '1.12.2-14.23.5.2859') { + throw new GradleException('Release manifest identity is incomplete or volatile') + } + + def metadataEntry = zip.getEntry('mcmod.info') + if (metadataEntry == null) { + throw new GradleException('Release jar is missing mcmod.info') + } + def metadata = new JsonSlurper().parseText( + zip.getInputStream(metadataEntry).getText(StandardCharsets.UTF_8.name())) + def mod = metadata instanceof List ? metadata.find { it.modid == 'basemetals' } : metadata + if (mod == null || mod.version != project.mod_version || mod.mcversion != project.minecraft_version) { + throw new GradleException('Packaged mcmod.info has the wrong mod or target version') + } + if (zip.getEntry('com/mcmoddev/basemetals/worldgen/BaseMetalsWorldgenProvider.class') == null + || zip.getEntry('assets/basemetals/orespawn/provider.json') != null + || zip.getEntry('assets/basemetals/orespawn/basemetals.json') != null + || names.any { it.contains('/integration/orespawn/') + || it.startsWith('com/mcmoddev/orespawn/') }) { + throw new GradleException('Release jar does not contain only the API-built OreSpawn 4.1 provider') + } + + List leakedPaths = [] + zip.entries().findAll { entry -> archiveTextSuffixes.any { entry.name.endsWith(it) } }.each { entry -> + String text = zip.getInputStream(entry).getText(StandardCharsets.UTF_8.name()) + if (text =~ /(?i)([A-Z]:\\Users\\|[A-Z]:\\BaseMetals|\/home\/runner\/|\/Users\/)/) { + leakedPaths.add(entry.name) + } + } + if (!leakedPaths.isEmpty()) { + throw new GradleException("Release jar leaks local paths in ${leakedPaths}") + } + } finally { + zip.close() + } + + def baselineArtifacts = configurations.legacyBaselineArtifact.resolvedConfiguration.resolvedArtifacts + if (baselineArtifacts.size() != 1) { + throw new GradleException("Expected one released Base Metals baseline, found ${baselineArtifacts.size()}") + } + File baseline = baselineArtifacts.first().file + String baselineHash = sha256(baseline) + if (baselineHash != project.legacy_basemetals_sha256) { + throw new GradleException("Released baseline SHA-256 is ${baselineHash}, expected " + + project.legacy_basemetals_sha256) + } + def entryInventory = { File jarFile -> + ZipFile candidate = new ZipFile(jarFile) + try { + candidate.entries().findAll { !it.isDirectory() }.collect { it.name }.sort() + } finally { + candidate.close() + } + } + List currentInventory = entryInventory(mainJar) + List legacyInventory = entryInventory(baseline) + List allowedAddedEntries = [ + // Base Metals' steel rail alternative previously had no + // recipe-book discovery advancement. + 'assets/basemetals/advancements/recipes/transportation/rail.json', + // Replaces MMDLib's client-only 1.12 crossbow firing path. + 'com/mcmoddev/basemetals/items/ItemBaseMetalsCrossbow.class', + // Applies the established material attack statistic to both + // components of Base Metals ranged attacks. + 'com/mcmoddev/basemetals/items/ItemBaseMetalsArrow.class', + 'com/mcmoddev/basemetals/items/ItemBaseMetalsBolt.class', + 'com/mcmoddev/basemetals/items/ItemBaseMetalsBow.class', + // Restores ItemHoe's vanilla material-name contract for + // compatibility consumers such as Ancient Warfare 2. + 'com/mcmoddev/basemetals/items/ItemBaseMetalsHoe.class', + 'com/mcmoddev/basemetals/items/MaterialRangedDamage.class', + // Replaces MMDLib's reference to a nonexistent bolt texture. + 'com/mcmoddev/basemetals/client/renderer/RenderBaseMetalsBolt.class', + // Exposes the existing BaseMetals.cfg through OreSpawn 4.1's + // client-only world-settings extension point. + 'com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen.class', + 'com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen$CategoryElement.class', + 'com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen$CategoryEntry.class', + 'com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen$CategoryScreen.class', + // Upgrade-safe content policy, filtering, loot and handshake. + 'com/mcmoddev/basemetals/content/ContentMode.class', + 'com/mcmoddev/basemetals/content/ContentPolicy.class', + 'com/mcmoddev/basemetals/content/MaterialForm.class', + 'com/mcmoddev/basemetals/loot/ContentModeLootCondition.class', + 'com/mcmoddev/basemetals/loot/ContentModeLootCondition$Serializer.class', + 'com/mcmoddev/basemetals/network/ClientContentModeConnectionHandler.class', + 'com/mcmoddev/basemetals/network/ContentModeMessage.class', + 'com/mcmoddev/basemetals/network/ContentModeNetwork.class', + 'com/mcmoddev/basemetals/network/ContentModeNetwork$ServerHandler.class', + 'com/mcmoddev/basemetals/recipe/ContentAcquisitionFilters.class', + 'com/mcmoddev/basemetals/recipe/PolicyCrusherRecipe.class', + 'com/mcmoddev/basemetals/recipe/PolicyRecipe.class', + 'com/mcmoddev/basemetals/worldgen/BaseMetalsWorldgenProvider.class', + 'assets/mmdlib/lang/en_us.lang', + 'assets/mmdlib/lang/es_es.lang' + ] + List allowedRemovedEntries = [ + // The historical CurseForge jar was signed and carried FML's + // generated cache. Neither belongs in a reproducible rebuild. + 'META-INF/MINECRAF.RSA', + 'META-INF/MINECRAF.SF', + 'META-INF/fml_cache_annotation.json', + 'META-INF/fml_cache_class_versions.json', + 'com/mcmoddev/orespawn/BaseMetalsOreSpawn.class', + 'com/mcmoddev/orespawn/package-info.class', + 'assets/basemetals/orespawn/basemetals.json', + // These source files were deliberately removed on master-1.12 + // after 2.5.0-rc2.332; the modernization does not resurrect them. + 'com/mcmoddev/basemetals/items/MMDToolEffects.class', + 'com/mcmoddev/basemetals/items/package-info.class' + ] + List unexpectedAdded = (currentInventory - legacyInventory) - allowedAddedEntries + List unexpectedRemoved = (legacyInventory - currentInventory) - allowedRemovedEntries + if (!unexpectedAdded.isEmpty() || !unexpectedRemoved.isEmpty() + || !allowedAddedEntries.every { currentInventory.contains(it) } + || !allowedRemovedEntries.every { legacyInventory.contains(it) }) { + throw new GradleException("Release inventory drifted from ${project.legacy_basemetals_version}; " + + "added=${unexpectedAdded.take(20)}, removed=${unexpectedRemoved.take(20)}") + } + } +} +tasks.register('writeReleaseChecksums') { + group = 'verification' + description = 'Writes SHA-256 checksums for the audited release jars.' + dependsOn tasks.named('verifyReleaseArtifacts') + def outputFile = layout.buildDirectory.file('release/SHA256SUMS') + inputs.files(providers.provider { + expectedReleaseFiles.get().collect { name -> + layout.buildDirectory.file("libs/${name}").get().asFile + } + }) + outputs.file(outputFile) + doLast { + File output = outputFile.get().asFile + output.parentFile.mkdirs() + File libs = layout.buildDirectory.dir('libs').get().asFile + String contents = expectedReleaseFiles.get().sort().collect { name -> + "${sha256(new File(libs, name))} ${name}" + }.join(System.lineSeparator()) + System.lineSeparator() + output.setText(contents, 'UTF-8') + } +} + +tasks.register('verifyPreparedReleaseArtifacts') { + group = 'verification' + description = 'Audits a previously built immutable release bundle before publication.' + doLast { + if (!preparedReleaseDir.isPresent()) { + throw new GradleException('preparedReleaseDir is required for prepared artifact publication') + } + File prepared = file(preparedReleaseDir.get()) + List expected = expectedReleaseFiles.get().sort() + List jars = (prepared.listFiles() ?: [] as File[]) + .findAll { it.name.endsWith('.jar') }.sort { it.name } + if (jars.collect { it.name } != expected || jars.any { it.length() == 0L }) { + throw new GradleException("Prepared release must contain exactly ${expected}") + } + File checksums = new File(prepared, 'SHA256SUMS') + File changelog = new File(prepared, 'CHANGELOG.txt') + if (!checksums.isFile() || !changelog.isFile()) { + throw new GradleException('Prepared release is missing SHA256SUMS or CHANGELOG.txt') + } + List actual = jars.collect { "${sha256(it)} ${it.name}" }.sort() + List declared = checksums.readLines('UTF-8').findAll { !it.trim().isEmpty() }.sort() + if (actual != declared) { + throw new GradleException('Prepared release checksums do not match the immutable jars') + } + } +} diff --git a/gradle/release/publishing.gradle b/gradle/release/publishing.gradle new file mode 100644 index 00000000..bd36bca4 --- /dev/null +++ b/gradle/release/publishing.gradle @@ -0,0 +1,77 @@ +def releaseJar = project.ext.baseMetalsBuild.releaseJar +def expectedReleaseFiles = project.ext.baseMetalsVerification.expectedReleaseFiles +def preparedReleaseDir = project.ext.baseMetalsVerification.preparedReleaseDir + +// Publishing is deliberately separate from building and remains guarded by explicit credentials. +def mavenUploadUrl = providers.environmentVariable('MAVEN_UPLOAD_URL') + .orElse('https://invalid.invalid/missing-maven-upload-url') +def mavenUploadUsername = providers.environmentVariable('MAVEN_UPLOAD_USERNAME') +def mavenUploadPassword = providers.environmentVariable('MAVEN_UPLOAD_PASSWORD') + +publishing { + publications { + mavenJava(MavenPublication) { + groupId = project.group.toString() + artifactId = base.archivesName.get() + version = project.version.toString() + if (preparedReleaseDir.isPresent()) { + File prepared = file(preparedReleaseDir.get()) + artifact(new File(prepared, expectedReleaseFiles.get()[0])) + artifact(new File(prepared, expectedReleaseFiles.get()[1])) { classifier = 'sources' } + artifact(new File(prepared, expectedReleaseFiles.get()[2])) { classifier = 'javadoc' } + } else { + artifact(releaseJar) + artifact(tasks.named('sourcesJar')) + artifact(tasks.named('javadocJar')) + } + pom { + name = 'Base Metals' + description = 'Common metals, alloys, tools, armor, and world generation for Minecraft.' + url = 'https://github.com/MinecraftModDevelopmentMods/BaseMetals' + licenses { + license { + name = 'GNU Lesser General Public License, Version 2.1' + url = 'https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt' + } + } + scm { + connection = 'scm:git:https://github.com/MinecraftModDevelopmentMods/BaseMetals.git' + developerConnection = 'scm:git:ssh://git@github.com/MinecraftModDevelopmentMods/BaseMetals.git' + url = 'https://github.com/MinecraftModDevelopmentMods/BaseMetals' + } + } + } + } + repositories { + maven { + name = 'release' + url = uri(mavenUploadUrl.get()) + credentials { + username = mavenUploadUsername.orNull ?: '' + password = mavenUploadPassword.orNull ?: '' + } + } + } +} + +tasks.register('validateMavenReleaseCredentials') { + group = 'publishing' + doLast { + if (!providers.environmentVariable('MAVEN_UPLOAD_URL').isPresent() + || !mavenUploadUsername.isPresent() || !mavenUploadPassword.isPresent()) { + throw new GradleException('MAVEN_UPLOAD_URL, MAVEN_UPLOAD_USERNAME, and MAVEN_UPLOAD_PASSWORD are required') + } + if (providers.environmentVariable('MAVEN_UPLOAD_URL').get().startsWith('file:')) { + throw new GradleException('Maven release publication must use a remote repository') + } + } +} + +tasks.withType(PublishToMavenRepository).configureEach { + dependsOn tasks.named('validateMavenReleaseCredentials') + if (preparedReleaseDir.isPresent()) { + dependsOn tasks.named('verifyPreparedReleaseArtifacts') + } else { + dependsOn tasks.named('verifyReleaseArtifacts') + } +} diff --git a/gradle/stage-legacy-dependencies.sh b/gradle/stage-legacy-dependencies.sh index 940402e1..6ecb6430 100644 --- a/gradle/stage-legacy-dependencies.sh +++ b/gradle/stage-legacy-dependencies.sh @@ -50,13 +50,18 @@ stage() { mkdir -p "$destination" stage mmdlib "$(value mmdlib_curse_project_id)" "$(value mmdlib_curse_file_id)" "$(value mmdlib_sha256)" -stage mmd-orespawn "$(value orespawn3_curse_project_id)" "$(value orespawn3_curse_file_id)" "$(value orespawn3_sha256)" stage mmd-orespawn "$(value orespawn4_curse_project_id)" "$(value orespawn4_curse_file_id)" "$(value orespawn4_sha256)" +stage mmd-orespawn "$(value orespawn3_curse_project_id)" "$(value orespawn3_curse_file_id)" "$(value orespawn3_sha256)" stage additional-loot-tables "$(value alt_curse_project_id)" "$(value alt_curse_file_id)" "$(value alt_sha256)" stage mantle "$(value mantle_curse_project_id)" "$(value mantle_curse_file_id)" "$(value mantle_sha256)" stage tinkers-construct "$(value tconstruct_curse_project_id)" "$(value tconstruct_curse_file_id)" "$(value tconstruct_sha256)" +stage taiga-tinkers-alloying-addon "$(value taiga_curse_project_id)" "$(value taiga_curse_file_id)" "$(value taiga_sha256)" stage constructs-armory "$(value conarm_curse_project_id)" "$(value conarm_curse_file_id)" "$(value conarm_sha256)" stage thaumcraft "$(value thaumcraft_curse_project_id)" "$(value thaumcraft_curse_file_id)" "$(value thaumcraft_sha256)" stage baubles "$(value baubles_curse_project_id)" "$(value baubles_curse_file_id)" "$(value baubles_sha256)" stage cofh-core "$(value cofhcore_curse_project_id)" "$(value cofhcore_curse_file_id)" "$(value cofhcore_sha256)" +stage cofh-world "$(value cofhworld_curse_project_id)" "$(value cofhworld_curse_file_id)" "$(value cofhworld_sha256)" +stage redstone-flux "$(value redstoneflux_curse_project_id)" "$(value redstoneflux_curse_file_id)" "$(value redstoneflux_sha256)" +stage ancient-warfare-2 "$(value ancientwarfare_curse_project_id)" "$(value ancientwarfare_curse_file_id)" "$(value ancientwarfare_sha256)" +stage codechicken-lib-1-8 "$(value codechickenlib_curse_project_id)" "$(value codechickenlib_curse_file_id)" "$(value codechickenlib_sha256)" stage base-metals "$(value legacy_basemetals_curse_project_id)" "$(value legacy_basemetals_curse_file_id)" "$(value legacy_basemetals_sha256)" diff --git a/gradle/verification/packaged-forge-cofh.gradle b/gradle/verification/packaged-forge-cofh.gradle new file mode 100644 index 00000000..68464403 --- /dev/null +++ b/gradle/verification/packaged-forge-cofh.gradle @@ -0,0 +1,113 @@ +import groovy.json.JsonSlurper + +def packagedForge = project.ext.baseMetalsPackagedForge +def dependencySpecs = packagedForge.dependencySpecs +def releaseJar = packagedForge.releaseJar +def java8Launcher = packagedForge.java8Launcher +def packagedRuntimeProbeJar = packagedForge.packagedRuntimeProbeJar +def originalArtifact = packagedForge.originalArtifact +def runtimeLogFailures = packagedForge.runtimeLogFailures +def stagePackagedForgeBase = packagedForge.stagePackagedForgeBase + +// The CoFH profile verifies coexistence with Base Metals OreSpawn rules disabled. +File cofhRunDirectory = file("${buildDir}/packaged-forge-cofh-world-run") +File cofhMarker = new File(cofhRunDirectory, 'basemetals-runtime-probe.properties') +def prepareCoFH = tasks.register('preparePackagedForgeCoFHWorldRuntime') { + group = 'verification' + dependsOn releaseJar + dependsOn packagedRuntimeProbeJar + dependsOn tasks.named('verifyReleaseDependencies') + doLast { + stagePackagedForgeBase(cofhRunDirectory) + File mods = new File(cofhRunDirectory, 'mods') + mods.mkdirs() + copy { from layout.buildDirectory.file("libs/BaseMetals-${project.version}.jar"); into mods } + copy { from layout.buildDirectory.file('runtime-probes/basemetals-runtime-probe.jar'); into mods } + [dependencySpecs.mmdlib, dependencySpecs.orespawn4, dependencySpecs.cofhcore, + dependencySpecs.cofhworld, dependencySpecs.redstoneflux].each { spec -> + copy { + from originalArtifact(configurations.legacyDependencyArtifacts, spec.coordinate) + into mods + } + } + File config = new File(cofhRunDirectory, 'config') + File cofhWorld = new File(config, 'cofh/world') + cofhWorld.mkdirs() + copy { + from file('docs/examples/basemetals-orespawn-disabled.json') + into config + rename { 'basemetals-orespawn.json' } + } + copy { + from file('src/test/resources/cofh/world/99_basemetals_issue_448.json') + into cofhWorld + } + } +} + +def previousCoFH = prepareCoFH +['Fresh', 'Reload'].each { phase -> + def dependencyTask = previousCoFH + def processTask = tasks.register("packagedForgeCoFHWorld${phase}Process", Exec) { + group = 'verification' + dependsOn dependencyTask + workingDir cofhRunDirectory + ByteArrayOutputStream console = new ByteArrayOutputStream() + doFirst { + console.reset() + cofhMarker.delete() + File javaExecutable = java8Launcher.get().executablePath.asFile + File forge = new File(cofhRunDirectory, + "forge-${project.minecraft_version}-${project.forge_version}-universal.jar") + commandLine javaExecutable, + '-Dforge.logging.console.level=info', + "-Dbasemetals.probe.phase=${phase.toLowerCase()}", + "-Dbasemetals.probe.expectedOrespawn=${project.orespawn4_version}", + '-Dbasemetals.probe.expectedCoFHWorld=true', + "-Dbasemetals.probe.marker=${cofhMarker.absolutePath}", + '-jar', forge, 'nogui' + standardOutput = console + errorOutput = console + } + doLast { + new File(cofhRunDirectory, "cofh-${phase.toLowerCase()}-console.txt") + .setText(console.toString('UTF-8'), 'UTF-8') + if (!cofhMarker.isFile()) { + throw new GradleException("CoFH World ${phase} probe marker is missing") + } + Properties result = new Properties() + cofhMarker.withInputStream { result.load(it) } + if (result.getProperty('cofhWorld') != 'true' + || result.getProperty('managedOres') != '0' + || Integer.parseInt(result.getProperty('cofhAntimony', '0')) <= 0) { + throw new GradleException("CoFH World ${phase} result is invalid: ${result}") + } + File worldProfile = new File(cofhRunDirectory, + 'world/serverconfig/orespawn-worldgen.json') + def profile = new JsonSlurper().parse(worldProfile) + def rules = profile.ores.findAll { id, rule -> id.startsWith('basemetals:legacy/') } + if (rules.size() != 11 || !rules.every { id, rule -> !rule.enabled }) { + throw new GradleException('The CoFH World profile did not keep every Base Metals rule disabled') + } + List failures = runtimeLogFailures(cofhRunDirectory) + if (!failures.isEmpty()) { + throw new GradleException("CoFH World ${phase} logged runtime failures:\n" + + failures.take(20).join('\n')) + } + } + } + previousCoFH = processTask +} + +tasks.register('packagedForgeCoFHWorldRuntimeTest') { + group = 'verification' + description = 'Proves CoFH World can generate Base Metals ore while every OreSpawn rule is disabled.' + dependsOn previousCoFH +} + +tasks.named('packagedForgeRuntimeTest') { + dependsOn tasks.named('packagedForgeMissingOreSpawnTest') + dependsOn tasks.named('packagedForgeOs3RejectionTest') + dependsOn tasks.named('packagedForgeMigrationRuntimeTest') + dependsOn tasks.named('packagedForgeCoFHWorldRuntimeTest') +} diff --git a/gradle/verification/packaged-forge-dependencies.gradle b/gradle/verification/packaged-forge-dependencies.gradle new file mode 100644 index 00000000..5542c1a3 --- /dev/null +++ b/gradle/verification/packaged-forge-dependencies.gradle @@ -0,0 +1,206 @@ +import groovy.json.JsonSlurper + +def packagedForge = project.ext.baseMetalsPackagedForge +def dependencySpecs = packagedForge.dependencySpecs +def releaseJar = packagedForge.releaseJar +def java8Launcher = packagedForge.java8Launcher +def packagedRuntimeProbeJar = packagedForge.packagedRuntimeProbeJar +def originalArtifact = packagedForge.originalArtifact +def runtimeLogFailures = packagedForge.runtimeLogFailures +def stagePackagedForgeBase = packagedForge.stagePackagedForgeBase + +// These profiles prove that OreSpawn is required and that an existing explicit profile remains authoritative. +File existingOverrideRun = file("${buildDir}/packaged-forge-existing-override-run") +File existingOverrideMarker = new File(existingOverrideRun, 'basemetals-runtime-probe.properties') +def prepareExistingOverride = tasks.register('preparePackagedForgeExistingOverrideRuntime') { + group = 'verification' + dependsOn releaseJar + dependsOn packagedRuntimeProbeJar + dependsOn tasks.named('verifyReleaseDependencies') + doLast { + stagePackagedForgeBase(existingOverrideRun) + File mods = new File(existingOverrideRun, 'mods') + mods.mkdirs() + copy { from layout.buildDirectory.file("libs/BaseMetals-${project.version}.jar"); into mods } + copy { from layout.buildDirectory.file('runtime-probes/basemetals-runtime-probe.jar'); into mods } + [dependencySpecs.mmdlib, dependencySpecs.orespawn4].each { spec -> + copy { + from originalArtifact(configurations.legacyDependencyArtifacts, spec.coordinate) + into mods + } + } + File config = new File(existingOverrideRun, 'config') + config.mkdirs() + def explicitOverride = new JsonSlurper().parse( + file('docs/examples/basemetals-orespawn-disabled.json')) + explicitOverride.ores.each { id, rule -> rule.enabled = true } + new File(config, 'basemetals-orespawn.json').setText( + groovy.json.JsonOutput.prettyPrint(groovy.json.JsonOutput.toJson(explicitOverride)) + + System.lineSeparator(), 'UTF-8') + } +} + +def previousExistingOverride = prepareExistingOverride +['Fresh', 'Reload'].each { phase -> + def dependencyTask = previousExistingOverride + def processTask = tasks.register("packagedForgeExistingOverride${phase}Process", Exec) { + group = 'verification' + dependsOn dependencyTask + workingDir existingOverrideRun + ByteArrayOutputStream console = new ByteArrayOutputStream() + doFirst { + console.reset() + existingOverrideMarker.delete() + File javaExecutable = java8Launcher.get().executablePath.asFile + File forge = new File(existingOverrideRun, + "forge-${project.minecraft_version}-${project.forge_version}-universal.jar") + commandLine javaExecutable, + '-Dforge.logging.console.level=info', + "-Dbasemetals.probe.phase=${phase.toLowerCase()}", + "-Dbasemetals.probe.expectedOrespawn=${project.orespawn4_version}", + "-Dbasemetals.probe.marker=${existingOverrideMarker.absolutePath}", + '-jar', forge, 'nogui' + standardOutput = console + errorOutput = console + } + doLast { + new File(existingOverrideRun, "existing-override-${phase.toLowerCase()}-console.txt") + .setText(console.toString('UTF-8'), 'UTF-8') + if (!existingOverrideMarker.isFile()) { + throw new GradleException("Existing OreSpawn 4 override ${phase} probe failed") + } + File override = new File(existingOverrideRun, 'config/basemetals-orespawn.json') + File worldProfile = new File(existingOverrideRun, + 'world/serverconfig/orespawn-worldgen.json') + if (!override.isFile() || !worldProfile.isFile()) { + throw new GradleException('Existing OreSpawn 4 override or world snapshot is missing') + } + def overrideJson = new JsonSlurper().parse(override) + def profile = new JsonSlurper().parse(worldProfile) + def overrideRules = overrideJson.ores.findAll { id, rule -> + id.startsWith('basemetals:legacy/') + } + def snapshotRules = profile.ores.findAll { id, rule -> + id.startsWith('basemetals:legacy/') + } + if (overrideRules.size() != 11 || snapshotRules.size() != 11 + || !snapshotRules.every { id, rule -> + rule.enabled && rule.source_provider == 'basemetals' + }) { + throw new GradleException('Existing OreSpawn 4 override did not retain eleven stable rules') + } + List failures = runtimeLogFailures(existingOverrideRun) + if (!failures.isEmpty()) { + throw new GradleException("Existing OreSpawn 4 override ${phase} logged runtime failures:\n" + + failures.take(20).join('\n')) + } + } + } + previousExistingOverride = processTask +} + +tasks.register('packagedForgeExistingOverrideRuntimeTest') { + group = 'verification' + description = 'Loads an existing translated OreSpawn 4 override and reloads its world snapshot.' + dependsOn previousExistingOverride +} + +tasks.named('packagedForgeRuntimeTest') { + dependsOn tasks.named('packagedForgeExistingOverrideRuntimeTest') +} + +File missingOreSpawnRun = file("${buildDir}/packaged-forge-missing-orespawn-run") +tasks.register('preparePackagedForgeMissingOreSpawnRuntime') { + group = 'verification' + dependsOn releaseJar + dependsOn tasks.named('verifyReleaseDependencies') + doLast { + stagePackagedForgeBase(missingOreSpawnRun) + File mods = new File(missingOreSpawnRun, 'mods') + mods.mkdirs() + copy { from layout.buildDirectory.file("libs/BaseMetals-${project.version}.jar"); into mods } + copy { + from originalArtifact(configurations.legacyDependencyArtifacts, + dependencySpecs.mmdlib.coordinate) + into mods + } + } +} +tasks.register('packagedForgeMissingOreSpawnTest', Exec) { + group = 'verification' + description = 'Proves Base Metals refuses to load when OreSpawn 4 is absent.' + dependsOn tasks.named('preparePackagedForgeMissingOreSpawnRuntime') + workingDir missingOreSpawnRun + ignoreExitValue = true + ByteArrayOutputStream console = new ByteArrayOutputStream() + doFirst { + console.reset() + File javaExecutable = java8Launcher.get().executablePath.asFile + File forge = new File(missingOreSpawnRun, + "forge-${project.minecraft_version}-${project.forge_version}-universal.jar") + commandLine javaExecutable, '-Dforge.logging.console.level=info', '-jar', forge, 'nogui' + standardOutput = console + errorOutput = console + } + doLast { + String output = console.toString('UTF-8') + new File(missingOreSpawnRun, 'missing-orespawn-console.txt').setText(output, 'UTF-8') + if (!output.contains('MissingModsException') + || !output.contains('basemetals') + || !output.contains('orespawn') + || !output.contains('4.1.0.112021')) { + throw new GradleException('Missing OreSpawn 4 was not rejected by the Base Metals version contract') + } + } +} + +File os3RejectionRun = file("${buildDir}/packaged-forge-os3-rejection-run") +tasks.register('preparePackagedForgeOs3RejectionRuntime') { + group = 'verification' + dependsOn releaseJar + dependsOn tasks.named('verifyReleaseDependencies') + doLast { + stagePackagedForgeBase(os3RejectionRun) + File mods = new File(os3RejectionRun, 'mods') + mods.mkdirs() + copy { from layout.buildDirectory.file("libs/BaseMetals-${project.version}.jar"); into mods } + copy { + from originalArtifact(configurations.legacyDependencyArtifacts, + dependencySpecs.mmdlib.coordinate) + into mods + } + copy { + from originalArtifact(configurations.orespawn3FixtureArtifact, + dependencySpecs.orespawn3.coordinate) + into mods + } + } +} + +tasks.register('packagedForgeOs3RejectionTest', Exec) { + group = 'verification' + description = 'Proves OreSpawn 3 no longer satisfies Base Metals runtime dependencies.' + dependsOn tasks.named('preparePackagedForgeOs3RejectionRuntime') + workingDir os3RejectionRun + ignoreExitValue = true + ByteArrayOutputStream console = new ByteArrayOutputStream() + doFirst { + console.reset() + File javaExecutable = java8Launcher.get().executablePath.asFile + File forge = new File(os3RejectionRun, + "forge-${project.minecraft_version}-${project.forge_version}-universal.jar") + commandLine javaExecutable, '-Dforge.logging.console.level=info', '-jar', forge, 'nogui' + standardOutput = console + errorOutput = console + } + doLast { + String output = console.toString('UTF-8') + new File(os3RejectionRun, 'os3-rejection-console.txt').setText(output, 'UTF-8') + if (!output.contains('MissingModsException') + || !output.contains('basemetals') + || !output.contains('orespawn') + || !output.contains('4.1.0.112021')) { + throw new GradleException('OreSpawn 3 was not rejected by the Base Metals version contract') + } + } +} diff --git a/gradle/verification/packaged-forge-migration.gradle b/gradle/verification/packaged-forge-migration.gradle new file mode 100644 index 00000000..741d3334 --- /dev/null +++ b/gradle/verification/packaged-forge-migration.gradle @@ -0,0 +1,122 @@ +import groovy.json.JsonSlurper + +def packagedForge = project.ext.baseMetalsPackagedForge +def dependencySpecs = packagedForge.dependencySpecs +def releaseJar = packagedForge.releaseJar +def java8Launcher = packagedForge.java8Launcher +def packagedRuntimeProbeJar = packagedForge.packagedRuntimeProbeJar +def originalArtifact = packagedForge.originalArtifact +def runtimeLogFailures = packagedForge.runtimeLogFailures +def stagePackagedForgeBase = packagedForge.stagePackagedForgeBase + +// Migration profiles cover stock and customized OreSpawn 3 configurations. +def migrationProfiles = [ + Stock: [fixture: 'basemetals-stock.json', copper: true, nickelFrequency: 1.0D], + Custom: [fixture: 'basemetals-custom.json', copper: false, nickelFrequency: 2.5D] +] + +migrationProfiles.each { profileName, migration -> + File runDirectory = file("${buildDir}/packaged-forge-migration-${profileName.toLowerCase()}-run") + File marker = new File(runDirectory, 'basemetals-runtime-probe.properties') + def prepareTask = tasks.register("preparePackagedForgeMigration${profileName}Runtime") { + group = 'verification' + dependsOn releaseJar + dependsOn packagedRuntimeProbeJar + dependsOn tasks.named('verifyReleaseDependencies') + doLast { + stagePackagedForgeBase(runDirectory) + File mods = new File(runDirectory, 'mods') + mods.mkdirs() + copy { from layout.buildDirectory.file("libs/BaseMetals-${project.version}.jar"); into mods } + copy { from layout.buildDirectory.file('runtime-probes/basemetals-runtime-probe.jar'); into mods } + [dependencySpecs.mmdlib, dependencySpecs.orespawn4].each { spec -> + copy { + from originalArtifact(configurations.legacyDependencyArtifacts, spec.coordinate) + into mods + } + } + File legacyDirectory = new File(runDirectory, 'config/orespawn3') + legacyDirectory.mkdirs() + copy { + from file("src/test/resources/orespawn3/${migration.fixture}") + into legacyDirectory + rename { 'basemetals.json' } + } + } + } + + def previous = prepareTask + ['Fresh', 'Reload'].each { phase -> + def dependencyTask = previous + def processTask = tasks.register( + "packagedForgeMigration${profileName}${phase}Process", Exec) { + group = 'verification' + dependsOn dependencyTask + workingDir runDirectory + ByteArrayOutputStream console = new ByteArrayOutputStream() + doFirst { + console.reset() + marker.delete() + File javaExecutable = java8Launcher.get().executablePath.asFile + File forge = new File(runDirectory, + "forge-${project.minecraft_version}-${project.forge_version}-universal.jar") + commandLine javaExecutable, + '-Dforge.logging.console.level=info', + "-Dbasemetals.probe.phase=${phase.toLowerCase()}", + "-Dbasemetals.probe.expectedOrespawn=${project.orespawn4_version}", + "-Dbasemetals.probe.marker=${marker.absolutePath}", + '-jar', forge, 'nogui' + standardOutput = console + errorOutput = console + } + doLast { + new File(runDirectory, + "migration-${profileName.toLowerCase()}-${phase.toLowerCase()}-console.txt") + .setText(console.toString('UTF-8'), 'UTF-8') + if (!marker.isFile()) { + throw new GradleException("${profileName} OS3 migration ${phase} probe failed") + } + File worldProfile = new File(runDirectory, + 'world/serverconfig/orespawn-worldgen.json') + File report = new File(runDirectory, 'config/orespawn-os3-migration-report.json') + if (!worldProfile.isFile() || !report.isFile()) { + throw new GradleException("${profileName} OS3 migration did not write its profile/report") + } + def profile = new JsonSlurper().parse(worldProfile) + def rules = profile.ores.findAll { id, rule -> + id.startsWith('basemetals:legacy/') + } + def copper = rules['basemetals:legacy/copper_ore'] + def nickel = rules['basemetals:legacy/nickel_ore'] + def nickelSettings = nickel.dimension_selectors['orespawn:all_except_nether_end'] + if (rules.size() != 11 || copper.enabled != migration.copper + || nickelSettings.frequency != migration.nickelFrequency) { + throw new GradleException("${profileName} OS3 values were not preserved without duplicates") + } + String latestLog = new File(runDirectory, 'logs/latest.log').getText('UTF-8') + if (!(latestLog =~ /worldgen provider 'basemetals' revision [12] is active/) + || !new File(runDirectory, 'config/orespawn3/basemetals.json').isFile()) { + throw new GradleException("${profileName} OS3 migration was destructive or inactive") + } + List failures = runtimeLogFailures(runDirectory) + if (!failures.isEmpty()) { + throw new GradleException("${profileName} OS3 migration logged runtime failures:\n" + + failures.take(20).join('\n')) + } + } + } + previous = processTask + } + tasks.register("packagedForgeMigration${profileName}RuntimeTest") { + group = 'verification' + description = "Migrates and reloads the ${profileName.toLowerCase()} OreSpawn 3 fixture." + dependsOn previous + } +} + +tasks.register('packagedForgeMigrationRuntimeTest') { + group = 'verification' + description = 'Qualifies stock, customized, disabled, and reloaded OreSpawn 3 migrations.' + dependsOn tasks.named('packagedForgeMigrationStockRuntimeTest') + dependsOn tasks.named('packagedForgeMigrationCustomRuntimeTest') +} diff --git a/gradle/verification/packaged-forge-tinkers.gradle b/gradle/verification/packaged-forge-tinkers.gradle new file mode 100644 index 00000000..3703e7b2 --- /dev/null +++ b/gradle/verification/packaged-forge-tinkers.gradle @@ -0,0 +1,266 @@ +import groovy.json.JsonSlurper + +def packagedForge = project.ext.baseMetalsPackagedForge +def dependencySpecs = packagedForge.dependencySpecs +def releaseJar = packagedForge.releaseJar +def java8Launcher = packagedForge.java8Launcher +def packagedTinkersRuntimeProbeJar = packagedForge.packagedTinkersRuntimeProbeJar +def validatePackagedForgeRoot = packagedForge.validatePackagedForgeRoot +def originalArtifact = packagedForge.originalArtifact +def runtimeLogFailures = packagedForge.runtimeLogFailures + +// Tinkers profiles exercise optional combinations and every content mode. +def tinkersCompatibilityProfiles = [ + WithoutTaiga: [display: 'Tinkers Construct without TAIGA', taiga: false, prismarine: true, + mode: 'high_fantasy'], + WithTaiga: [display: 'Tinkers Construct with TAIGA', taiga: true, prismarine: true, + mode: 'high_fantasy'], + WithConArm: [display: "Tinkers Construct with Construct's Armory", taiga: false, + conarm: true, prismarine: true, mode: 'high_fantasy'], + PrismarineDisabled: [display: 'Tinkers Construct with Prismarine disabled', taiga: false, + prismarine: false, mode: 'high_fantasy'], + LowFantasy: [display: 'Tinkers Construct in Low Fantasy mode', taiga: false, + prismarine: true, mode: 'low_fantasy'], + LowFantasyConArm: [display: "Tinkers Construct and Construct's Armory in Low Fantasy mode", + taiga: false, conarm: true, prismarine: true, mode: 'low_fantasy'], + Realism: [display: 'Tinkers Construct in Realism mode', taiga: false, + prismarine: true, mode: 'realism'], + RealismConArm: [display: "Tinkers Construct and Construct's Armory in Realism mode", + taiga: false, conarm: true, prismarine: true, mode: 'realism'], + RealismExplicitOverride: [display: 'Realism with an explicit enabled OreSpawn override', + taiga: false, prismarine: true, mode: 'realism', preserveEnabledOres: true, + explicitOverride: true], + RealismExistingWorld: [display: 'a High Fantasy world restarted in Realism mode', + taiga: false, prismarine: true, mode: 'high_fantasy', reloadMode: 'realism', + preserveEnabledOres: true] +] + +tinkersCompatibilityProfiles.each { profileName, profile -> + File runDirectory = file("${buildDir}/packaged-forge-tinkers-${profileName.toLowerCase()}-run") + File marker = new File(runDirectory, 'basemetals-tinkers-runtime-probe.properties') + def prepareTask = tasks.register("preparePackagedForgeTinkers${profileName}Runtime") { + group = 'verification' + dependsOn releaseJar + dependsOn packagedTinkersRuntimeProbeJar + dependsOn tasks.named('verifyReleaseDependencies') + doLast { + delete runDirectory + File sourceRuntime = validatePackagedForgeRoot() + File forge = new File(sourceRuntime, + "forge-${project.minecraft_version}-${project.forge_version}-universal.jar") + java.util.jar.JarFile forgeJar = new java.util.jar.JarFile(forge) + String declaredClasspath + try { + declaredClasspath = forgeJar.manifest.mainAttributes.getValue('Class-Path') + } finally { + forgeJar.close() + } + if (declaredClasspath == null || declaredClasspath.trim().isEmpty()) { + throw new GradleException("Forge runtime has no Class-Path manifest entry: ${forge}") + } + copy { from forge; into runDirectory } + copy { + from new File(sourceRuntime, "minecraft_server.${project.minecraft_version}.jar") + into runDirectory + } + declaredClasspath.trim().split(/\s+/).findAll { + it != "minecraft_server.${project.minecraft_version}.jar" + }.each { String entry -> + String relative = entry.startsWith('libraries/') + ? entry.substring('libraries/'.length()) : entry + File dependency = new File(sourceRuntime, "libraries/${relative}") + if (!dependency.isFile()) { + throw new GradleException("Forge runtime dependency is missing: ${dependency}") + } + copy { from dependency; into new File(runDirectory, "libraries/${relative}").parentFile } + } + File mods = new File(runDirectory, 'mods') + mods.mkdirs() + copy { from layout.buildDirectory.file("libs/BaseMetals-${project.version}.jar"); into mods } + copy { + from layout.buildDirectory.file('runtime-probes/basemetals-tinkers-runtime-probe.jar') + into mods + } + [dependencySpecs.mmdlib, dependencySpecs.orespawn4, + dependencySpecs.mantle, dependencySpecs.tconstruct].each { spec -> + copy { from originalArtifact(configurations.legacyDependencyArtifacts, spec.coordinate); into mods } + } + if (profile.taiga) { + copy { + from originalArtifact(configurations.legacyDependencyArtifacts, + dependencySpecs.taiga.coordinate) + into mods + } + } + if (profile.conarm) { + copy { + from originalArtifact(configurations.legacyDependencyArtifacts, + dependencySpecs.conarm.coordinate) + into mods + } + } + if (!profile.prismarine || profile.mode != 'high_fantasy') { + File configDirectory = new File(runDirectory, 'config') + configDirectory.mkdirs() + StringBuilder config = new StringBuilder() + if (profile.mode != 'high_fantasy') { + config.append('general {\n') + .append(' S:contentMode=') + .append(profile.mode) + .append('\n}\n\n') + } + if (!profile.prismarine) { + config.append('fluids {\n') + .append(' B:"Enabled Prismarine"=true\n') + .append('}\n\n') + .append('vanilla {\n') + .append(' B:EnablePrismarine=false\n') + .append('}\n') + } + new File(configDirectory, 'BaseMetals.cfg').setText(config.toString(), 'UTF-8') + } + if (profile.explicitOverride) { + File configDirectory = new File(runDirectory, 'config') + configDirectory.mkdirs() + def explicitOverride = new JsonSlurper().parse( + file('docs/examples/basemetals-orespawn-disabled.json')) + explicitOverride.ores.each { id, rule -> rule.enabled = true } + new File(configDirectory, 'basemetals-orespawn.json').setText( + groovy.json.JsonOutput.prettyPrint( + groovy.json.JsonOutput.toJson(explicitOverride)) + + System.lineSeparator(), 'UTF-8') + } + new File(runDirectory, 'server.properties').setText('''\ +level-name=world +level-seed=basemetals-tinkers-compatibility +level-type=default +online-mode=false +server-port=0 +allow-nether=false +generate-structures=false +spawn-protection=0 +max-tick-time=-1 +''', 'UTF-8') + new File(runDirectory, 'eula.txt').setText('eula=true\n', 'UTF-8') + } + } + + def previous = prepareTask + ['Fresh', 'Reload'].each { phase -> + def dependencyTask = previous + def processTask = tasks.register("packagedForgeTinkers${profileName}${phase}Process", Exec) { + group = 'verification' + dependsOn dependencyTask + workingDir runDirectory + ByteArrayOutputStream console = new ByteArrayOutputStream() + doFirst { + console.reset() + marker.delete() + String effectiveMode = phase == 'Reload' && profile.reloadMode + ? profile.reloadMode : profile.mode + if (phase == 'Reload' && profile.reloadMode) { + File configFile = new File(runDirectory, 'config/BaseMetals.cfg') + String configText = configFile.getText('UTF-8') + String changed = configText.replace( + 'S:contentMode=high_fantasy', + "S:contentMode=${profile.reloadMode}") + if (changed == configText) { + throw new GradleException("Could not change the existing-world content mode in ${configFile}") + } + configFile.setText(changed, 'UTF-8') + } + File javaExecutable = java8Launcher.get().executablePath.asFile + File forge = new File(runDirectory, + "forge-${project.minecraft_version}-${project.forge_version}-universal.jar") + commandLine javaExecutable, + '-Dforge.logging.console.level=info', + "-Dbasemetals.probe.phase=${phase.toLowerCase()}", + "-Dbasemetals.probe.expectedTaiga=${profile.taiga}", + "-Dbasemetals.probe.expectedConArm=${profile.conarm == true}", + "-Dbasemetals.probe.expectedPrismarine=${profile.prismarine}", + "-Dbasemetals.probe.expectedContentMode=${effectiveMode}", + "-Dbasemetals.probe.marker=${marker.absolutePath}", + '-jar', forge, 'nogui' + standardOutput = console + errorOutput = console + } + doLast { + new File(runDirectory, + "tinkers-${profileName.toLowerCase()}-${phase.toLowerCase()}-console.txt") + .setText(console.toString('UTF-8'), 'UTF-8') + if (!marker.isFile()) { + throw new GradleException("${profile.display} ${phase} probe marker is missing") + } + Properties result = new Properties() + marker.withInputStream { result.load(it) } + String effectiveMode = phase == 'Reload' && profile.reloadMode + ? profile.reloadMode : profile.mode + if (result.getProperty('phase') != phase.toLowerCase() + || result.getProperty('registered') != 'true' + || result.getProperty('taiga') != profile.taiga.toString() + || result.getProperty('conarm') != (profile.conarm == true).toString() + || result.getProperty('prismarine') != profile.prismarine.toString() + || result.getProperty('contentMode') != effectiveMode) { + throw new GradleException("${profile.display} ${phase} probe result is invalid: ${result}") + } + File worldProfile = new File(runDirectory, + 'world/serverconfig/orespawn-worldgen.json') + if (!worldProfile.isFile()) { + throw new GradleException("${profile.display} did not snapshot the world profile") + } + def generated = new JsonSlurper().parse(worldProfile) + def generatedRules = generated.ores.findAll { id, rule -> + id.startsWith('basemetals:legacy/') + } + Set disabledRules = generatedRules.findAll { id, rule -> !rule.enabled } + .keySet() as Set + Set expectedDisabledRules = !profile.preserveEnabledOres + && effectiveMode == 'realism' + ? ['basemetals:legacy/adamantine_ore', + 'basemetals:legacy/coldiron_ore', + 'basemetals:legacy/starsteel_ore'] as Set + : [] as Set + if (generatedRules.size() != 11 || disabledRules != expectedDisabledRules) { + throw new GradleException("${profile.display} loaded unexpected Base Metals rule defaults: " + + "disabled=${disabledRules}, expected=${expectedDisabledRules}") + } + String latestLog = new File(runDirectory, 'logs/latest.log').getText('UTF-8') + if (latestLog.contains('Fallback Ore Spawn Generator Enabled!') + || latestLog.contains('Loading Integration For basemetals') + || !latestLog.contains("worldgen provider 'basemetals' revision 2 is active")) { + throw new GradleException("${profile.display} did not retain OreSpawn ownership") + } + List failures = runtimeLogFailures(runDirectory) + if (!failures.isEmpty()) { + throw new GradleException("${profile.display} ${phase} logged runtime failures:\n" + + failures.take(20).join('\n')) + } + } + } + previous = processTask + } + tasks.register("packagedForgeTinkers${profileName}RuntimeTest") { + group = 'verification' + description = "Creates and reloads a packaged Forge world with ${profile.display}." + dependsOn previous + } +} + +tasks.register('packagedForgeTinkersCompatibilityTest') { + group = 'verification' + description = 'Qualifies Tinkers behavior across optional-mod and content-mode profiles.' + dependsOn tasks.named('packagedForgeTinkersWithoutTaigaRuntimeTest') + dependsOn tasks.named('packagedForgeTinkersWithTaigaRuntimeTest') + dependsOn tasks.named('packagedForgeTinkersWithConArmRuntimeTest') + dependsOn tasks.named('packagedForgeTinkersPrismarineDisabledRuntimeTest') + dependsOn tasks.named('packagedForgeTinkersLowFantasyRuntimeTest') + dependsOn tasks.named('packagedForgeTinkersLowFantasyConArmRuntimeTest') + dependsOn tasks.named('packagedForgeTinkersRealismRuntimeTest') + dependsOn tasks.named('packagedForgeTinkersRealismConArmRuntimeTest') + dependsOn tasks.named('packagedForgeTinkersRealismExplicitOverrideRuntimeTest') + dependsOn tasks.named('packagedForgeTinkersRealismExistingWorldRuntimeTest') +} + +tasks.named('packagedForgeRuntimeTest') { + dependsOn tasks.named('packagedForgeTinkersCompatibilityTest') +} diff --git a/gradle/verification/packaged-forge.gradle b/gradle/verification/packaged-forge.gradle new file mode 100644 index 00000000..8a4aa0d3 --- /dev/null +++ b/gradle/verification/packaged-forge.gradle @@ -0,0 +1,372 @@ +import groovy.json.JsonSlurper + +def dependencySpecs = project.ext.baseMetalsDependencies.specs +def releaseJar = project.ext.baseMetalsBuild.releaseJar +def java8Launcher = project.ext.baseMetalsVerification.java8Launcher + +// Packaged tests run the release jar in clean Forge installations, not against IDE output. +tasks.register('runtimeProbeJar', Jar) { + group = 'verification' + description = 'Builds the mapped test-only packaged-runtime acceptance probe.' + dependsOn tasks.named('testClasses') + archiveBaseName = 'basemetals-runtime-probe' + archiveVersion = '' + archiveClassifier = 'deobf' + destinationDirectory = layout.buildDirectory.dir('runtime-probes-dev') + from(sourceSets.test.output) { + include 'com/mcmoddev/basemetals/test/BaseMetalsRuntimeProbe*.class' + } +} + +def packagedRuntimeProbeJar = renamer.classes(tasks.named('runtimeProbeJar', Jar)) { + map.from minecraft.dependency.toSrgFile + archiveClassifier = null + output = layout.buildDirectory.file('runtime-probes/basemetals-runtime-probe.jar') +} + +tasks.register('packagedRuntimeProbes') { + group = 'verification' + dependsOn packagedRuntimeProbeJar +} + +tasks.register('tinkersRuntimeProbeJar', Jar) { + group = 'verification' + description = 'Builds the mapped test-only Tinkers/TAIGA compatibility probe.' + dependsOn tasks.named('testClasses') + archiveBaseName = 'basemetals-tinkers-runtime-probe' + archiveVersion = '' + archiveClassifier = 'deobf' + destinationDirectory = layout.buildDirectory.dir('runtime-probes-dev') + from(sourceSets.test.output) { + include 'com/mcmoddev/basemetals/test/BaseMetalsTinkersRuntimeProbe*.class' + } +} + +tasks.register('clientConfigRuntimeProbeJar', Jar) { + group = 'verification' + description = 'Builds the mapped test-only OreSpawn client configuration probe.' + dependsOn tasks.named('testClasses') + archiveBaseName = 'basemetals-client-config-runtime-probe' + archiveVersion = '' + archiveClassifier = 'deobf' + destinationDirectory = layout.buildDirectory.dir('runtime-probes-dev') + from(sourceSets.test.output) { + include 'com/mcmoddev/basemetals/test/BaseMetalsClientConfigRuntimeProbe*.class' + } +} + +def packagedClientConfigRuntimeProbeJar = renamer.classes( + tasks.named('clientConfigRuntimeProbeJar', Jar)) { + map.from minecraft.dependency.toSrgFile + archiveClassifier = null + output = layout.buildDirectory.file( + 'runtime-probes/basemetals-client-config-runtime-probe.jar') +} + +tasks.register('packagedClientConfigRuntimeProbe') { + group = 'verification' + description = 'Builds the test-only packaged-client probe used for OreSpawn cog qualification.' + dependsOn packagedClientConfigRuntimeProbeJar +} + +def packagedTinkersRuntimeProbeJar = renamer.classes(tasks.named('tinkersRuntimeProbeJar', Jar)) { + map.from minecraft.dependency.toSrgFile + archiveClassifier = null + output = layout.buildDirectory.file('runtime-probes/basemetals-tinkers-runtime-probe.jar') +} + +def packagedForgeRuntimeRoot = providers.gradleProperty('packagedForgeRuntimeRoot') +def validatePackagedForgeRoot = { + if (!packagedForgeRuntimeRoot.isPresent()) { + throw new GradleException('packagedForgeRuntimeRoot is required for packaged Forge qualification') + } + File root = file(packagedForgeRuntimeRoot.get()) + [ + new File(root, "forge-${project.minecraft_version}-${project.forge_version}-universal.jar"), + new File(root, "minecraft_server.${project.minecraft_version}.jar"), + new File(root, 'libraries') + ].each { required -> + if (!required.exists()) { + throw new GradleException("Packaged Forge runtime is missing ${required}") + } + } + root +} + +def originalArtifact = { Configuration configuration, String coordinate -> + String[] bits = coordinate.split(':') + def matches = configuration.resolvedConfiguration.resolvedArtifacts.findAll { + it.moduleVersion.id.group == bits[0] + && it.moduleVersion.id.name == bits[1] + && it.moduleVersion.id.version == bits[2] + } + if (matches.size() != 1) { + throw new GradleException("Expected exactly ${coordinate}, found ${matches*.moduleVersion*.id}") + } + matches.first().file +} + +def runtimeLogFailures = { File runDirectory -> + List fatalMarkers = [ + 'Encountered an unexpected exception', 'LoaderException', 'NoClassDefFoundError', + 'NoSuchMethodError', 'NoSuchFieldError', 'IllegalAccessError', 'LinkageError', + 'Parsing error loading recipe', + 'Exception stopping the server', 'The following mod(s) have been identified as potential causes' + ] + List failures = [] + fileTree(runDirectory) { + include 'logs/**/*.log' + include '*-console.txt' + }.files.each { log -> + int lineNumber = 0 + log.eachLine('UTF-8') { line -> + lineNumber++ + if (fatalMarkers.any { line.contains(it) }) { + failures.add("${log.name}:${lineNumber}: ${line}") + } + } + } + failures +} + +def packagedStacks = [ + Os4: [ + display: 'OreSpawn 4', + modVersion: project.orespawn4_version, + expectedAncientWarfare: false, + extraMods: [], + coordinate: dependencySpecs.orespawn4.coordinate + ], + AncientWarfare: [ + display: 'OreSpawn 4 plus Ancient Warfare 2', + modVersion: project.orespawn4_version, + expectedAncientWarfare: true, + extraMods: [dependencySpecs.ancientwarfare, dependencySpecs.codechickenlib], + coordinate: dependencySpecs.orespawn4.coordinate + ] +] + +packagedStacks.each { stackName, stack -> + File runDirectory = file("${buildDir}/packaged-forge-${stackName.toLowerCase()}-run") + File marker = new File(runDirectory, 'basemetals-runtime-probe.properties') + def prepareTask = tasks.register("preparePackagedForge${stackName}Runtime") { + group = 'verification' + dependsOn releaseJar + dependsOn packagedRuntimeProbeJar + dependsOn tasks.named('verifyReleaseDependencies') + doLast { + delete runDirectory + File sourceRuntime = validatePackagedForgeRoot() + File forge = new File(sourceRuntime, + "forge-${project.minecraft_version}-${project.forge_version}-universal.jar") + java.util.jar.JarFile forgeJar = new java.util.jar.JarFile(forge) + String declaredClasspath + try { + declaredClasspath = forgeJar.manifest.mainAttributes.getValue('Class-Path') + } finally { + forgeJar.close() + } + if (declaredClasspath == null || declaredClasspath.trim().isEmpty()) { + throw new GradleException("Forge runtime has no Class-Path manifest entry: ${forge}") + } + copy { from forge; into runDirectory } + copy { + from new File(sourceRuntime, "minecraft_server.${project.minecraft_version}.jar") + into runDirectory + } + declaredClasspath.trim().split(/\s+/).findAll { + it != "minecraft_server.${project.minecraft_version}.jar" + }.each { String entry -> + String relative = entry.startsWith('libraries/') + ? entry.substring('libraries/'.length()) : entry + File dependency = new File(sourceRuntime, "libraries/${relative}") + if (!dependency.isFile()) { + throw new GradleException("Forge runtime dependency is missing: ${dependency}") + } + copy { from dependency; into new File(runDirectory, "libraries/${relative}").parentFile } + } + File mods = new File(runDirectory, 'mods') + mods.mkdirs() + copy { from layout.buildDirectory.file("libs/BaseMetals-${project.version}.jar"); into mods } + copy { from layout.buildDirectory.file('runtime-probes/basemetals-runtime-probe.jar'); into mods } + copy { + from originalArtifact(configurations.legacyDependencyArtifacts, + dependencySpecs.mmdlib.coordinate) + into mods + } + copy { + from originalArtifact(configurations.legacyDependencyArtifacts, stack.coordinate) + into mods + } + stack.extraMods.each { spec -> + copy { + from originalArtifact(configurations.legacyDependencyArtifacts, spec.coordinate) + into mods + } + } + new File(runDirectory, 'server.properties').setText('''\ +level-name=world +level-seed=basemetals-release-modernization +level-type=default +online-mode=false +server-port=0 +allow-nether=false +generate-structures=false +spawn-protection=0 +max-tick-time=-1 +''', 'UTF-8') + new File(runDirectory, 'eula.txt').setText('eula=true\n', 'UTF-8') + } + } + + def previous = prepareTask + ['Fresh', 'Reload'].each { phase -> + def dependencyTask = previous + def processTask = tasks.register("packagedForge${stackName}${phase}Process", Exec) { + group = 'verification' + dependsOn dependencyTask + workingDir runDirectory + ByteArrayOutputStream console = new ByteArrayOutputStream() + doFirst { + console.reset() + marker.delete() + File javaExecutable = java8Launcher.get().executablePath.asFile + File forge = new File(runDirectory, + "forge-${project.minecraft_version}-${project.forge_version}-universal.jar") + commandLine javaExecutable, + '-Dforge.logging.console.level=info', + "-Dbasemetals.probe.phase=${phase.toLowerCase()}", + "-Dbasemetals.probe.expectedOrespawn=${stack.modVersion}", + "-Dbasemetals.probe.expectedAncientWarfare=${stack.expectedAncientWarfare}", + "-Dbasemetals.probe.marker=${marker.absolutePath}", + '-jar', forge, 'nogui' + standardOutput = console + errorOutput = console + } + doLast { + new File(runDirectory, + "${stackName.toLowerCase()}-${phase.toLowerCase()}-console.txt") + .setText(console.toString('UTF-8'), 'UTF-8') + if (!marker.isFile()) { + throw new GradleException("${stack.display} ${phase} probe marker is missing") + } + Properties result = new Properties() + marker.withInputStream { result.load(it) } + if (result.getProperty('phase') != phase.toLowerCase() + || result.getProperty('registered') != 'true' + || result.getProperty('orespawn') != stack.modVersion + || result.getProperty('ancientWarfare') + != stack.expectedAncientWarfare.toString()) { + throw new GradleException("${stack.display} ${phase} probe result is invalid: ${result}") + } + File worldProfile = new File(runDirectory, + 'world/serverconfig/orespawn-worldgen.json') + if (!worldProfile.isFile()) { + throw new GradleException("${stack.display} did not snapshot the world profile") + } + def profile = new JsonSlurper().parse(worldProfile) + def generatedRules = profile.ores.findAll { id, rule -> + id.startsWith('basemetals:legacy/') + } + if (generatedRules.size() != 11 + || !generatedRules.every { id, rule -> + rule.enabled && rule.source_provider == 'basemetals' + }) { + throw new GradleException("${stack.display} did not snapshot eleven enabled native rules") + } + String latestLog = new File(runDirectory, 'logs/latest.log').getText('UTF-8') + if (latestLog.contains('Fallback Ore Spawn Generator Enabled!') + || latestLog.contains('Loading Integration For basemetals') + || !latestLog.contains("worldgen provider 'basemetals' revision 2 is active")) { + throw new GradleException("${stack.display} did not take exclusive ownership of Base Metals ore generation") + } + List failures = runtimeLogFailures(runDirectory) + if (!failures.isEmpty()) { + throw new GradleException("${stack.display} ${phase} logged runtime failures:\n" + + failures.take(20).join('\n')) + } + } + } + previous = processTask + } + tasks.register("packagedForge${stackName}RuntimeTest") { + group = 'verification' + description = "Creates and reloads a packaged Forge world with ${stack.display}." + dependsOn previous + } +} + +tasks.register('packagedForgeRuntimeTest') { + group = 'verification' + description = 'Runs supported OreSpawn 4 fresh/reload packaged-server qualification.' + dependsOn tasks.named('packagedForgeOs4RuntimeTest') + dependsOn tasks.named('packagedForgeAncientWarfareRuntimeTest') +} + +def stagePackagedForgeBase = { File runDirectory -> + project.delete(runDirectory) + File sourceRuntime = validatePackagedForgeRoot() + File forge = new File(sourceRuntime, + "forge-${project.minecraft_version}-${project.forge_version}-universal.jar") + java.util.jar.JarFile forgeJar = new java.util.jar.JarFile(forge) + String declaredClasspath + try { + declaredClasspath = forgeJar.manifest.mainAttributes.getValue('Class-Path') + } finally { + forgeJar.close() + } + if (declaredClasspath == null || declaredClasspath.trim().isEmpty()) { + throw new GradleException("Forge runtime has no Class-Path manifest entry: ${forge}") + } + project.copy { from forge; into runDirectory } + project.copy { + from new File(sourceRuntime, "minecraft_server.${project.minecraft_version}.jar") + into runDirectory + } + declaredClasspath.trim().split(/\s+/).findAll { + it != "minecraft_server.${project.minecraft_version}.jar" + }.each { String entry -> + String relative = entry.startsWith('libraries/') + ? entry.substring('libraries/'.length()) : entry + File dependency = new File(sourceRuntime, "libraries/${relative}") + if (!dependency.isFile()) { + throw new GradleException("Forge runtime dependency is missing: ${dependency}") + } + project.copy { + from dependency + into new File(runDirectory, "libraries/${relative}").parentFile + } + } + new File(runDirectory, 'server.properties').setText('''\ +level-name=world +level-seed=basemetals-issue-448 +level-type=default +online-mode=false +server-port=0 +allow-nether=false +generate-structures=false +spawn-protection=0 +max-tick-time=-1 +''', 'UTF-8') + new File(runDirectory, 'eula.txt').setText('eula=true\n', 'UTF-8') +} + +ext.baseMetalsPackagedForge = [ + dependencySpecs : dependencySpecs, + releaseJar : releaseJar, + java8Launcher : java8Launcher, + packagedRuntimeProbeJar : packagedRuntimeProbeJar, + packagedTinkersRuntimeProbeJar : packagedTinkersRuntimeProbeJar, + packagedClientConfigRuntimeProbeJar : packagedClientConfigRuntimeProbeJar, + packagedForgeRuntimeRoot : packagedForgeRuntimeRoot, + validatePackagedForgeRoot : validatePackagedForgeRoot, + originalArtifact : originalArtifact, + runtimeLogFailures : runtimeLogFailures, + packagedStacks : packagedStacks, + stagePackagedForgeBase : stagePackagedForgeBase +].asImmutable() + +apply from: 'gradle/verification/packaged-forge-dependencies.gradle' +apply from: 'gradle/verification/packaged-forge-migration.gradle' +apply from: 'gradle/verification/packaged-forge-cofh.gradle' +apply from: 'gradle/verification/packaged-forge-tinkers.gradle' diff --git a/gradle/verification/support.gradle b/gradle/verification/support.gradle new file mode 100644 index 00000000..aac89495 --- /dev/null +++ b/gradle/verification/support.gradle @@ -0,0 +1,269 @@ +import groovy.json.JsonSlurper +import java.nio.charset.StandardCharsets +import java.security.MessageDigest +import java.util.zip.ZipFile + +def buildContract = project.ext.baseMetalsBuild +def dependencySpecs = project.ext.baseMetalsDependencies.specs +def expectedMavenGroup = buildContract.mavenGroup +def expectedMavenArtifact = buildContract.mavenArtifact +def expectedMavenCoordinate = buildContract.mavenCoordinate + +// Shared release checks belong here so every release-facing task uses one contract. +def java8Launcher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(8) + vendor = JvmVendorSpec.ADOPTIUM +} + +def java25Launcher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(25) + vendor = JvmVendorSpec.ADOPTIUM +} + +tasks.register('verifyReleaseToolchains') { + group = 'verification' + description = 'Requires the pinned Gradle, Mavenizer, compilation, and runtime JDKs.' + doLast { + String gradleVendor = System.getProperty('java.vendor') + String gradleRuntime = System.getProperty('java.runtime.version') + if (project.gradle_java_version != '17' + || gradleVendor != 'Eclipse Adoptium' + || gradleRuntime != '17.0.1+12') { + throw new GradleException("Expected Gradle on Temurin 17.0.1+12, found " + + "${gradleVendor} ${gradleRuntime} at ${System.getProperty('java.home')}") + } + + def metadata = java8Launcher.get().metadata + if (project.java_toolchain_version != '8.0.502+7' + || metadata.vendor.toString() != 'Eclipse Temurin' + || metadata.javaRuntimeVersion != '1.8.0_502-b07') { + throw new GradleException("Expected Temurin ${project.java_toolchain_version}, found " + + "${metadata.vendor} ${metadata.javaRuntimeVersion} at ${metadata.installationPath}") + } + + def mavenizerMetadata = java25Launcher.get().metadata + if (project.mavenizer_java_version != '25.0.3+9' + || mavenizerMetadata.vendor.toString() != 'Eclipse Temurin' + || mavenizerMetadata.javaRuntimeVersion != '25.0.3+9-LTS') { + throw new GradleException("Expected Mavenizer on Temurin ${project.mavenizer_java_version}, found " + + "${mavenizerMetadata.vendor} ${mavenizerMetadata.javaRuntimeVersion} " + + "at ${mavenizerMetadata.installationPath}") + } + } +} + +tasks.named('check') { + dependsOn tasks.named('verifyReleaseToolchains') +} + +def expectedReleaseFiles = providers.provider { + def prefix = "${base.archivesName.get()}-${project.version}" + [ + "${prefix}.jar", + "${prefix}-sources.jar", + "${prefix}-javadoc.jar" + ] +} +def preparedReleaseDir = providers.gradleProperty('preparedReleaseDir') + +def sha256 = { File candidate -> + MessageDigest digest = MessageDigest.getInstance('SHA-256') + candidate.withInputStream { input -> + byte[] buffer = new byte[8192] + for (int read = input.read(buffer); read >= 0; read = input.read(buffer)) { + if (read > 0) digest.update(buffer, 0, read) + } + } + digest.digest().encodeHex().toString().toUpperCase() +} + +tasks.register('verifyReleaseConfiguration') { + group = 'verification' + description = 'Validates the complete Base Metals 1.12 release identity and dependency contract.' + dependsOn tasks.named('verifyReleaseToolchains') + doLast { + if (project.mod_version != '2.6.0.112021' + || project.minecraft_version != '1.12.2' + || project.forge_version != '14.23.5.2859' + || project.mappings_channel != 'stable' + || project.mappings_version != '39-1.12') { + throw new GradleException('Unexpected Base Metals version, Minecraft, Forge, or mappings target') + } + String buildScript = file('build.gradle').getText('UTF-8') + String settingsScript = file('settings.gradle').getText('UTF-8') + Properties wrapper = new Properties() + file('gradle/wrapper/gradle-wrapper.properties').withInputStream { wrapper.load(it) } + if (!buildScript.contains("id 'net.minecraftforge.gradle' version '7.0.34'") + || !buildScript.contains("id 'net.minecraftforge.renamer' version '1.1.5'") + || !settingsScript.contains("version '1.0.0'") + || wrapper.getProperty('distributionUrl') + != 'https://services.gradle.org/distributions/gradle-9.6.1-bin.zip' + || wrapper.getProperty('distributionSha256Sum') + != '9c0f7faeeb306cb14e4279a3e084ca6b596894089a0638e68a07c945a32c9e14') { + throw new GradleException('ForgeGradle, Renamer, Foojay, or Gradle wrapper identity drifted') + } + if (project.loader_name != 'forge' || project.loader_code != '1' + || project.java_version != '8' + || project.java_toolchain_version != '8.0.502+7' + || project.gradle_java_version != '17' + || project.mavenizer_java_version != '25.0.3+9') { + throw new GradleException('Unexpected loader or Java release metadata') + } + if (project.mod_group != expectedMavenGroup + || base.archivesName.get() != expectedMavenArtifact + || "${project.group}:${base.archivesName.get()}:${project.version}" != expectedMavenCoordinate) { + throw new GradleException("Unexpected Maven coordinate; expected ${expectedMavenCoordinate}") + } + if (project.cf_project_id != '240967' + || project.cf_requirements != 'mmd-orespawn,mmdlib' + || project.cf_versions != '1.12.2') { + throw new GradleException('Unexpected CurseForge publication contract') + } + if (dependencySpecs.mmdlib.version != '1.0.0-rc2.36' + || dependencySpecs.orespawn4.version != '4.1.0.112021' + || dependencySpecs.orespawn3.version != '3.3.1.179') { + throw new GradleException('Unexpected MMDLib, OreSpawn 4, or OreSpawn 3 fixture version') + } + if (project.orespawn4_curse_project_id != '245586' + || project.orespawn4_curse_file_id != '9008120' + || project.orespawn4_sha256 != 'B3018214BD1A612309A78DF02C552C0948A8FCD3CF314F25D40071E8B4605670') { + throw new GradleException('Unexpected published OreSpawn 4.1 CurseForge artifact identity') + } + String source = file('src/main/java/com/mcmoddev/basemetals/BaseMetals.java').getText('UTF-8') + if (!source.contains('VERSION = "2.6.0.112021"') + || !source.contains('certificateFingerprint = ""') + || !source.contains('required-after:orespawn@[4.1.0.112021,5.0.0)')) { + throw new GradleException('Base Metals source version or unsigned fingerprint contract drifted') + } + } +} + +tasks.register('verifyReleaseDependencies') { + group = 'verification' + description = 'Resolves and checksum-verifies all exact legacy mod dependencies.' + dependsOn tasks.named('verifyReleaseConfiguration') + doLast { + def resolved = configurations.legacyDependencyArtifacts.resolvedConfiguration.resolvedArtifacts + def supportedSpecs = dependencySpecs.findAll { name, spec -> name != 'orespawn3' } + if (resolved.size() != supportedSpecs.size()) { + throw new GradleException("Expected ${supportedSpecs.size()} exact supported/test artifacts, found ${resolved.size()}") + } + supportedSpecs.each { name, spec -> + def bits = spec.coordinate.split(':') + def matches = resolved.findAll { + it.moduleVersion.id.group == bits[0] + && it.moduleVersion.id.name == bits[1] + && it.moduleVersion.id.version == bits[2] + } + if (matches.size() != 1) { + throw new GradleException("Expected exactly ${spec.coordinate}, found ${matches*.moduleVersion*.id}") + } + String actual = sha256(matches.first().file) + if (actual != spec.sha256) { + throw new GradleException("${name} SHA-256 is ${actual}, expected ${spec.sha256}") + } + } + def os3Resolved = configurations.orespawn3FixtureArtifact.resolvedConfiguration.resolvedArtifacts + if (os3Resolved.size() != 1) { + throw new GradleException("Expected one isolated OreSpawn 3 fixture, found ${os3Resolved*.moduleVersion*.id}") + } + String os3Actual = sha256(os3Resolved.first().file) + if (os3Actual != dependencySpecs.orespawn3.sha256) { + throw new GradleException("orespawn3 SHA-256 is ${os3Actual}, expected ${dependencySpecs.orespawn3.sha256}") + } + def orespawn4Bits = dependencySpecs.orespawn4.coordinate.split(':') + File orespawn4 = resolved.find { + it.moduleVersion.id.group == orespawn4Bits[0] + && it.moduleVersion.id.name == orespawn4Bits[1] + && it.moduleVersion.id.version == orespawn4Bits[2] + }.file + ZipFile compatibilityJar = new ZipFile(orespawn4) + try { + def entry = compatibilityJar.getEntry('mcmod.info') + def metadata = entry == null ? null : new JsonSlurper().parseText( + compatibilityJar.getInputStream(entry).getText(StandardCharsets.UTF_8.name())) + def mod = metadata instanceof List ? metadata.find { it.modid == 'orespawn' } : metadata + if (mod == null || mod.version != project.orespawn4_version) { + throw new GradleException("OreSpawn 4 compatibility artifact is not ${project.orespawn4_version}") + } + [ + 'zone/moddev/mc/orespawn/api/client/WorldSettingsExtensionRegistry.class', + 'zone/moddev/mc/orespawn/api/client/WorldSettingsScreenFactory.class' + ].each { apiClass -> + if (compatibilityJar.getEntry(apiClass) == null) { + throw new GradleException("OreSpawn 4 release is missing client API ${apiClass}") + } + } + } finally { + compatibilityJar.close() + } + } +} + +tasks.register('verifyJsonResources') { + group = 'verification' + description = 'Parses every production JSON resource.' + inputs.files(fileTree('src/main/resources') { include '**/*.json' }) + doLast { + fileTree('src/main/resources') { include '**/*.json' }.files.sort().each { candidate -> + try { + new JsonSlurper().parse(candidate) + } catch (Exception failure) { + throw new GradleException("Invalid JSON resource ${project.relativePath(candidate)}", failure) + } + } + } +} + +tasks.named('check') { + dependsOn tasks.named('verifyReleaseConfiguration') + dependsOn tasks.named('verifyReleaseDependencies') + dependsOn tasks.named('verifyJsonResources') +} + +tasks.register('verifyOreSpawnProviderConfiguration') { + group = 'verification' + description = 'Locks the schema-5 API provider and complete disabled override contract.' + inputs.file('src/main/java/com/mcmoddev/basemetals/worldgen/BaseMetalsWorldgenProvider.java') + inputs.file('docs/examples/basemetals-orespawn-disabled.json') + doLast { + def disabled = new JsonSlurper().parse( + file('docs/examples/basemetals-orespawn-disabled.json')) + List expectedRules = [ + 'basemetals:legacy/coldiron_ore', 'basemetals:legacy/adamantine_ore', + 'basemetals:legacy/starsteel_ore', 'basemetals:legacy/copper_ore', + 'basemetals:legacy/silver_ore', 'basemetals:legacy/tin_ore', + 'basemetals:legacy/lead_ore', 'basemetals:legacy/zinc_ore', + 'basemetals:legacy/mercury_ore', 'basemetals:legacy/nickel_ore', + 'basemetals:legacy/platinum_ore' + ].sort() + String source = file('src/main/java/com/mcmoddev/basemetals/worldgen/BaseMetalsWorldgenProvider.java') + .getText('UTF-8') + if (!source.contains('PROVIDER_REVISION = 2') + || !source.contains('mergeNewEntriesIntoExistingWorlds(true)') + || disabled.schema_version != 5 || disabled.provider_modid != 'basemetals' + || disabled.provider_revision != 2 + || disabled.merge_new_entries_into_existing_worlds != true + || disabled.ores.keySet().sort() != expectedRules) { + throw new GradleException('The API-built or disabled OreSpawn provider has the wrong identity') + } + if (!disabled.ores.every { id, rule -> !rule.enabled } + || file('src/main/resources/assets/basemetals/orespawn/provider.json').exists() + || file('src/main/resources/assets/basemetals/orespawn/basemetals.json').exists() + || file('src/main/java/com/mcmoddev/basemetals/integration/orespawn/BaseMetalsOreSpawn.java').exists()) { + throw new GradleException('The disabled provider is incomplete or a static/OS3 provider remains') + } + } +} + +tasks.named('check') { + dependsOn tasks.named('verifyOreSpawnProviderConfiguration') +} + +ext.baseMetalsVerification = [ + java8Launcher : java8Launcher, + java25Launcher : java25Launcher, + expectedReleaseFiles: expectedReleaseFiles, + preparedReleaseDir : preparedReleaseDir, + sha256 : sha256 +].asImmutable() diff --git a/gradle/verification/workflows.gradle b/gradle/verification/workflows.gradle new file mode 100644 index 00000000..65a2f5a1 --- /dev/null +++ b/gradle/verification/workflows.gradle @@ -0,0 +1,54 @@ +// Keep workflow validation close to the workflow contracts it protects. +tasks.register('verifyWorkflowContracts') { + group = 'verification' + description = 'Validates pinned CI, tag, and multi-target release-dispatcher contracts.' + inputs.files(fileTree('.github/workflows') { include '*.yml' }) + doLast { + Map> required = [ + 'ci.yml': [ + 'master-1.12', 'feature/**', 'Cold Forge bootstrap', + 'Build, test, and audit', 'stage-legacy-dependencies.sh', + 'packagedForgeRuntimeTest', 'prepareEclipse', + 'Verify reproducible release archives' + ], + 'codeql-analysis.yml': [ + 'master-1.12', 'feature/**', 'github/codeql-action/init@', + 'stage-legacy-dependencies.sh', 'clean classes' + ], + 'validate-gradle-build.yml': [ + 'master-1.12', 'feature/**', 'gradle/actions/wrapper-validation@' + ], + 'release-on-tag.yml': [ + "tags:\n - '*.*.*.*'", 'Build, test, and audit', + 'deploy-release.yml', '**Nothing has been published.**' + ], + 'deploy-release.yml': [ + 'master-1.12)', 'master-1.18)', + 'stage-legacy-dependencies.sh', 'stage-orespawn-release.sh', + "mmdlib) curseforge_dependencies+=('261744(required)')", + 'confirm_live_publication' + ] + ] + required.each { name, fragments -> + File workflow = file(".github/workflows/${name}") + if (!workflow.isFile()) { + throw new GradleException("Missing workflow ${name}") + } + String text = workflow.getText('UTF-8').replace('\r\n', '\n') + List missing = fragments.findAll { !text.contains(it) } + if (!missing.isEmpty()) { + throw new GradleException("${name} is missing contract fragments ${missing}") + } + text.eachLine { line -> + def match = line =~ /^\s*uses:\s*([^\s#]+)(?:\s+#.*)?$/ + if (match.matches() && !(match.group(1) ==~ /[^@]+@[0-9a-f]{40}/)) { + throw new GradleException("${name} has an unpinned action: ${line.trim()}") + } + } + } + } +} + +tasks.named('check') { + dependsOn tasks.named('verifyWorkflowContracts') +} diff --git a/src/main/java/com/mcmoddev/alt/BaseMetalsALT.java b/src/main/java/com/mcmoddev/alt/BaseMetalsALT.java index c855e2fe..416a3404 100644 --- a/src/main/java/com/mcmoddev/alt/BaseMetalsALT.java +++ b/src/main/java/com/mcmoddev/alt/BaseMetalsALT.java @@ -4,7 +4,7 @@ import com.mcmoddev.alt.api.IALTPlugin; import com.mcmoddev.basemetals.BaseMetals; +/** Marker used by Additional Loot Tables to discover Base Metals' bundled tables. */ @ALTPlugin(modid = BaseMetals.MODID) class BaseMetalsALT implements IALTPlugin { - // Intentionally left blank } diff --git a/src/main/java/com/mcmoddev/basemetals/BaseMetals.java b/src/main/java/com/mcmoddev/basemetals/BaseMetals.java index 35cc458b..880f0323 100644 --- a/src/main/java/com/mcmoddev/basemetals/BaseMetals.java +++ b/src/main/java/com/mcmoddev/basemetals/BaseMetals.java @@ -5,6 +5,7 @@ import com.mcmoddev.basemetals.proxy.CommonProxy; import com.mcmoddev.basemetals.util.BMeConfig; +import com.mcmoddev.basemetals.worldgen.BaseMetalsWorldgenProvider; import com.mcmoddev.lib.data.SharedStrings; import net.minecraft.block.Block; @@ -22,41 +23,12 @@ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** - *

BaseMetals:

- * - Forge Mod entry point
- * This entry point handles basic Forge events for the initialization phases of Base Metals; - * the handling the remapping of items and blocks; - * and the construction of Base Metals addons/plugins.
- *
- * Annotation Info:
- * - Dependencies:
- *      - Forge [v 14.21.1.2387 or higher] (loads after)
- *      - Tinkers Construct [any] (loads after)
- *      - IC2 [any] (loads after)
- *      - Building Bricks [any] (loads before)
- * - Minecraft Versions: 1.12 or greater
- *
- * Project pages:
- * -
github
- * - curse forge - *

- * - *

Notes for BaseMetals addons:

- * - Make sure to include 'dependencies = "required-after:basemetals"' to your Mod's @Mod annotation.
- * (e.g. @Mod(modid = "moremetals", name="More Metals!", version = "1.2.3", dependencies = "required-after:basemetals") - *

- * Classes of interest: - * @see com.mcmoddev.basemetals.init - * @see com.mcmoddev.lib.registry.CrusherRecipeRegistry - * @author Jasmine Iwanek - * @author Java doc author: Vase of Petunias - */ +/** Forge entry point for Base Metals. */ @Mod( modid = BaseMetals.MODID, name = BaseMetals.NAME, version = BaseMetals.VERSION, - dependencies = "required-after:forge@[14.23.1.2592,);required-after:mmdlib;after:tconstruct;after:conarm;after:thaumcraft;after:ic2;before:buildingbricks", + dependencies = "required-after:forge@[14.23.5.2859,);required-after:mmdlib;required-after:orespawn@[4.1.0.112021,5.0.0);after:tconstruct;after:conarm;after:thaumcraft;after:ic2;before:buildingbricks", acceptedMinecraftVersions = "[1.12,1.12.2]", certificateFingerprint = "", updateJSON = BaseMetals.UPDATEJSON) @@ -65,24 +37,14 @@ public final class BaseMetals { @Instance public static BaseMetals instance; - /** - * Mod ID used by forge in the @Mod annotation. - */ + /** Stable mod identifier used by Forge and saved registry names. */ public static final String MODID = "basemetals"; - /** - * Used in the @Mod annotation.
- * This is the vanity display name that will appear to users of the mod. - * (e.g. The mods menu in game) - */ + /** Display name shown by Forge. */ protected static final String NAME = "Base Metals"; - /** - * Version format: Major.Minor.Patch
- * The Minor version number will be increased when ever there is potential for compatibility issues - * with dependant mods. - */ - protected static final String VERSION = "2.5.1.112021"; + /** Release version in the shared MMD major.minor.patch.target format. */ + protected static final String VERSION = "2.6.0.112021"; protected static final String UPDATEJSON = SharedStrings.UPDATE_JSON_URL + "BaseMetals/master/update.json"; @@ -98,96 +60,54 @@ public final class BaseMetals { public static final Logger logger = LogManager.getFormatterLogger(BaseMetals.MODID); static { - // Forge says this needs to be statically initialized here. + // Forge requires universal buckets to be enabled before fluid registration begins. FluidRegistry.enableUniversalBucket(); } - /** - * @return Returns the current version of the mod. - */ + /** Returns the current Base Metals version. */ public static String getVersion() { return VERSION; } - /** - * Called when Forge sets up Base Metals:
- * - This method will set up all addons for Base Metals.
- * Refer to {@link com.mcmoddev.lib.integration.IntegrationManager#doSetupTasks(FMLConstructionEvent)} documentation. - *
- * - Initializes Base Metals config {@link Config#init()}. - *

- * Errors:
- * Errors occur when ever there was an issue loading a Base Metals plugin. - * @param event The event representing the construction of Base Metals. - */ + /** Loads configuration early enough for registration decisions. */ @EventHandler public static void constructing(final FMLConstructionEvent event) { BMeConfig.init(); } - /** - * Logs a warning when ever the mod finger print does not match the certificate loaded from the mod jar. - * @param event The event that represents the finger print violation. - */ + /** Reports a jar whose signing certificate does not match Forge's expectation. */ @EventHandler public void onFingerprintViolation(final FMLFingerprintViolationEvent event) { logger.warn(SharedStrings.INVALID_FINGERPRINT); } - /** - * Pre-initialization of Base Metals:
- * Kicks off the initialization process of Base Metals.
- * Refer to {@link CommonProxy#preInit(FMLPreInitializationEvent)} documentation for what goes on - * during the pre-initialization procedure. - * - * @param event The event representing the pre-initialization phase of Forge. - */ + /** Starts side-specific setup and registers common event handlers. */ @EventHandler public static void preInit(final FMLPreInitializationEvent event) { proxy.preInit(event); } - /** - * Initialization of Base Metals:
- * Refer to {@link CommonProxy#init(FMLInitializationEvent)} documentation for what goes on - * during the initialization procedure. - * - * @param event The event representing the initialization phase of Forge. - */ + /** Gives OreSpawn the provider before completing normal mod initialization. */ @EventHandler public static void init(final FMLInitializationEvent event) { + if (!BaseMetalsWorldgenProvider.enqueue()) { + throw new IllegalStateException("OreSpawn rejected the Base Metals provider"); + } proxy.init(event); } - /** - * Post-initialization of Base Metals:
- * Refer to {@link CommonProxy#postInit(FMLPostInitializationEvent)} documentation for what goes on - * during the post-initialization procedure. - * - * @param event The event representing the post-initialization phase of Forge. - */ @EventHandler public static void postInit(final FMLPostInitializationEvent event) { proxy.postInit(event); } - /** - * Fired when ever a block in Forged has been remapped.
- * Refer to {@link CommonProxy#onRemapBlock(RegistryEvent.MissingMappings)} documentation as to how remapped blocks are handled. - * - * @param event The event representing a list of missing mapped blocks that need to be remapped. - */ + /** Restores historical block IDs when Forge loads an older save. */ @SubscribeEvent public void onRemapBlock(final RegistryEvent.MissingMappings event) { proxy.onRemapBlock(event); } - /** - * Fired when ever an item in Forged has been remapped.
- * Refer to {@link CommonProxy#onRemapItem(RegistryEvent.MissingMappings)} documentation as to how remapped items are handled. - * - * @param event The event representing a list of missing mapped items that need to be remapped. - */ + /** Restores historical item IDs when Forge loads an older save. */ @SubscribeEvent public void onRemapItem(final RegistryEvent.MissingMappings event) { proxy.onRemapItem(event); diff --git a/src/main/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen.java b/src/main/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen.java new file mode 100644 index 00000000..fca4a297 --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen.java @@ -0,0 +1,220 @@ +package com.mcmoddev.basemetals.client.config; + +import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.content.ContentMode; +import com.mcmoddev.basemetals.util.BMeConfig; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiYesNo; +import net.minecraft.client.gui.GuiYesNoCallback; +import net.minecraft.client.resources.I18n; +import net.minecraftforge.common.config.ConfigCategory; +import net.minecraftforge.common.config.ConfigElement; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.common.config.Property; +import net.minecraftforge.fml.client.config.GuiConfig; +import net.minecraftforge.fml.client.config.GuiConfigEntries; +import net.minecraftforge.fml.client.config.IConfigElement; +import org.lwjgl.input.Keyboard; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** Forge-native editor for the existing BaseMetals.cfg configuration. */ +public final class BaseMetalsConfigScreen extends GuiConfig implements GuiYesNoCallback { + + private static final int CONFIRM_CHANGES = 4701; + + private final Configuration configuration; + private final Map initialValues; + private GuiButton pendingDoneButton; + + public BaseMetalsConfigScreen(final GuiScreen parent) { + this(parent, BMeConfig.getConfiguration()); + } + + BaseMetalsConfigScreen(final GuiScreen parent, final Configuration configuration) { + super(parent, categoryElements(configuration), BaseMetals.MODID, BaseMetals.MODID, + false, true, I18n.format("config.basemetals.title"), + I18n.format("config.basemetals.restart_guidance")); + this.configuration = configuration; + this.initialValues = snapshot(configuration); + } + + static List categoryElements(final Configuration configuration) { + final List elements = new ArrayList<>(); + for (final String categoryName : BMeConfig.GUI_CATEGORIES) { + elements.add(new CategoryElement(configuration.getCategory(categoryName))); + } + return elements; + } + + static Map snapshot(final Configuration configuration) { + final Map values = new LinkedHashMap<>(); + for (final String categoryName : BMeConfig.GUI_CATEGORIES) { + final ConfigCategory category = configuration.getCategory(categoryName); + for (final Map.Entry property : category.getValues().entrySet()) { + values.put(key(categoryName, property.getKey()), property.getValue().getString()); + } + } + return values; + } + + static List disabledGeneratedRules(final Map before, + final Configuration configuration) { + final List disabled = new ArrayList<>(); + for (final Map.Entry generated : BMeConfig.getGeneratedOreRules().entrySet()) { + final String propertyName = BMeConfig.getMaterialPropertyName(generated.getKey()); + final String snapshotKey = key(BMeConfig.MATERIALS_CAT, propertyName); + final Property property = configuration.getCategory(BMeConfig.MATERIALS_CAT) + .get(propertyName); + if (Boolean.parseBoolean(before.get(snapshotKey)) && !property.getBoolean()) { + disabled.add(generated.getValue()); + } + } + return disabled; + } + + @Override + protected void actionPerformed(final GuiButton button) { + if (button.id == 2000 && entryList.hasChangedEntry(true)) { + // Child category entries retain their pending values until the root Done + // action. Apply them temporarily so the material/OreSpawn relationship + // can be checked, then restore the backing Configuration while the + // confirmation is open. + entryList.saveConfigElements(); + final ContentMode initialMode = ContentMode.fromSerializedName(initialValues.get( + key(BMeConfig.GENERAL_CAT, BMeConfig.CONTENT_MODE_PROPERTY))); + final ContentMode selectedMode = BMeConfig.configuredContentMode(configuration); + final List disabledRules = disabledGeneratedRules(initialValues, configuration); + if (initialMode != selectedMode || !disabledRules.isEmpty()) { + restoreInitialValues(); + pendingDoneButton = button; + final String title; + String message; + if (initialMode != selectedMode) { + title = I18n.format("config.basemetals.warning.content_mode.title"); + final String detailKey = selectedMode == ContentMode.REALISM + ? "config.basemetals.warning.content_mode.realism" + : "config.basemetals.warning.content_mode.message"; + message = I18n.format(detailKey, + I18n.format(initialMode.translationKey()), + I18n.format(selectedMode.translationKey())); + if (!disabledRules.isEmpty()) { + message += "\n\n" + I18n.format( + "config.basemetals.warning.disable_ores.message", + String.join(", ", disabledRules)); + } + } else { + title = I18n.format("config.basemetals.warning.disable_ores.title"); + message = I18n.format("config.basemetals.warning.disable_ores.message", + String.join(", ", disabledRules)); + } + mc.displayGuiScreen(new GuiYesNo(this, + title, message, + I18n.format("config.basemetals.warning.confirm"), + I18n.format("gui.cancel"), CONFIRM_CHANGES)); + return; + } + } + super.actionPerformed(button); + } + + @Override + public void confirmClicked(final boolean result, final int id) { + if (id != CONFIRM_CHANGES) { + return; + } + mc.displayGuiScreen(this); + if (result && pendingDoneButton != null) { + super.actionPerformed(pendingDoneButton); + } + pendingDoneButton = null; + } + + @Override + protected void keyTyped(final char eventChar, final int eventKey) { + if (eventKey == Keyboard.KEY_ESCAPE) { + entryList.undoAllChanges(true); + restoreInitialValues(); + mc.displayGuiScreen(parentScreen); + return; + } + super.keyTyped(eventChar, eventKey); + } + + void restoreInitialValues() { + restore(initialValues, configuration); + } + + static void restore(final Map values, + final Configuration configuration) { + for (final String categoryName : BMeConfig.GUI_CATEGORIES) { + final ConfigCategory category = configuration.getCategory(categoryName); + for (final Map.Entry property : category.getValues().entrySet()) { + final String value = values.get(key(categoryName, property.getKey())); + if (value != null) { + property.getValue().set(value); + } + } + } + } + + private static String key(final String category, final String property) { + return category + '\u0000' + property; + } + + private static final class CategoryElement extends ConfigElement { + CategoryElement(final ConfigCategory category) { + super(category); + } + + @Override + public Class getConfigEntryClass() { + return CategoryEntry.class; + } + } + + /** Category button that creates an Escape-safe child configuration page. */ + public static final class CategoryEntry extends GuiConfigEntries.CategoryEntry { + public CategoryEntry(final GuiConfig owningScreen, + final GuiConfigEntries owningEntryList, + final IConfigElement configElement) { + super(owningScreen, owningEntryList, configElement); + } + + @Override + protected GuiScreen buildChildScreen() { + return new CategoryScreen(owningScreen, configElement.getChildElements(), + owningScreen.modID, + owningScreen.allRequireWorldRestart || configElement.requiresWorldRestart(), + owningScreen.allRequireMcRestart || configElement.requiresMcRestart(), + owningScreen.title, + (owningScreen.titleLine2 == null ? "" : owningScreen.titleLine2) + + " > " + name); + } + } + + /** Nested page whose Escape action truly discards that page's edits. */ + public static final class CategoryScreen extends GuiConfig { + CategoryScreen(final GuiScreen parent, final List elements, + final String modId, final boolean requiresWorldRestart, + final boolean requiresMcRestart, final String title, + final String titleLine2) { + super(parent, elements, modId, null, requiresWorldRestart, + requiresMcRestart, title, titleLine2); + } + + @Override + protected void keyTyped(final char eventChar, final int eventKey) { + if (eventKey == Keyboard.KEY_ESCAPE) { + entryList.undoAllChanges(true); + mc.displayGuiScreen(parentScreen); + return; + } + super.keyTyped(eventChar, eventKey); + } + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/client/renderer/RenderBaseMetalsBolt.java b/src/main/java/com/mcmoddev/basemetals/client/renderer/RenderBaseMetalsBolt.java new file mode 100644 index 00000000..4736117d --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/client/renderer/RenderBaseMetalsBolt.java @@ -0,0 +1,38 @@ +package com.mcmoddev.basemetals.client.renderer; + +import com.mcmoddev.lib.client.renderer.RenderCustomBolt; +import com.mcmoddev.lib.entity.EntityCustomBolt; + +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +/** + * Renders MMDLib bolts with Minecraft's existing projectile texture. + * + *

MMDLib requests {@code minecraft:textures/entity/projectiles/bolt.png}, + * which does not exist in Minecraft 1.12.2. The bolt and arrow renderers use + * the same geometry and UV layout, so the vanilla arrow texture is the + * compatible replacement.

+ */ +@SideOnly(Side.CLIENT) +public final class RenderBaseMetalsBolt extends RenderCustomBolt { + + private static final ResourceLocation PROJECTILE_TEXTURE = + new ResourceLocation("minecraft", "textures/entity/projectiles/arrow.png"); + + /** + * Creates the Base Metals bolt renderer. + * + * @param renderManager Minecraft's entity render manager + */ + public RenderBaseMetalsBolt(final RenderManager renderManager) { + super(renderManager); + } + + @Override + protected ResourceLocation getEntityTexture(final EntityCustomBolt entity) { + return PROJECTILE_TEXTURE; + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/content/ContentMode.java b/src/main/java/com/mcmoddev/basemetals/content/ContentMode.java new file mode 100644 index 00000000..36736033 --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/content/ContentMode.java @@ -0,0 +1,66 @@ +package com.mcmoddev.basemetals.content; + +import java.util.Locale; + +/** Stable content-policy modes stored in {@code BaseMetals.cfg} and sent over the network. */ +public enum ContentMode { + HIGH_FANTASY("high_fantasy"), + LOW_FANTASY("low_fantasy"), + REALISM("realism"); + + private final String serializedName; + + ContentMode(final String serializedName) { + this.serializedName = serializedName; + } + + public String serializedName() { + return serializedName; + } + + public String translationKey() { + return "config.basemetals.content_mode." + serializedName; + } + + public static ContentMode fromSerializedName(final String value) { + if (value != null) { + final String normalized = value.trim().toLowerCase(Locale.ROOT); + for (final ContentMode mode : values()) { + if (mode.serializedName.equals(normalized)) { + return mode; + } + } + } + return HIGH_FANTASY; + } + + public static boolean isValidSerializedName(final String value) { + if (value == null) { + return false; + } + for (final ContentMode mode : values()) { + if (mode.serializedName.equals(value.trim().toLowerCase(Locale.ROOT))) { + return true; + } + } + return false; + } + + public static String[] serializedNames() { + final ContentMode[] modes = values(); + final String[] names = new String[modes.length]; + for (int i = 0; i < modes.length; i++) { + names[i] = modes[i].serializedName; + } + return names; + } + + public static String[] translationKeys() { + final ContentMode[] modes = values(); + final String[] names = new String[modes.length]; + for (int i = 0; i < modes.length; i++) { + names[i] = modes[i].translationKey(); + } + return names; + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/content/ContentPolicy.java b/src/main/java/com/mcmoddev/basemetals/content/ContentPolicy.java new file mode 100644 index 00000000..9ef40eb9 --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/content/ContentPolicy.java @@ -0,0 +1,244 @@ +package com.mcmoddev.basemetals.content; + +import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.data.MaterialNames; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Locale; +import java.util.Set; + +/** Immutable, reviewed material-by-form acquisition policy. */ +public final class ContentPolicy { + private static final Set MATERIALS = set( + MaterialNames.ADAMANTINE, MaterialNames.ANTIMONY, MaterialNames.AQUARIUM, + MaterialNames.BISMUTH, MaterialNames.BRASS, MaterialNames.BRONZE, + MaterialNames.CHARCOAL, MaterialNames.COAL, MaterialNames.COLDIRON, + MaterialNames.COPPER, MaterialNames.CUPRONICKEL, MaterialNames.DIAMOND, + MaterialNames.ELECTRUM, MaterialNames.EMERALD, MaterialNames.ENDER, + MaterialNames.GOLD, MaterialNames.INVAR, MaterialNames.IRON, + MaterialNames.LAPIS, MaterialNames.LEAD, MaterialNames.MERCURY, + MaterialNames.MITHRIL, MaterialNames.NICKEL, MaterialNames.OBSIDIAN, + MaterialNames.PEWTER, MaterialNames.PLATINUM, MaterialNames.PRISMARINE, + MaterialNames.QUARTZ, MaterialNames.REDSTONE, MaterialNames.SILVER, + MaterialNames.STARSTEEL, MaterialNames.STEEL, MaterialNames.STONE, + MaterialNames.TIN, MaterialNames.WOOD, MaterialNames.ZINC); + + private static final Set MYTHICAL = set(MaterialNames.ADAMANTINE, + MaterialNames.AQUARIUM, MaterialNames.COLDIRON, MaterialNames.MITHRIL, + MaterialNames.STARSTEEL); + + private static final Set FULL_TOOLS = set(MaterialNames.ADAMANTINE, + MaterialNames.AQUARIUM, MaterialNames.BRONZE, MaterialNames.COLDIRON, + MaterialNames.COPPER, MaterialNames.CUPRONICKEL, MaterialNames.INVAR, + MaterialNames.MITHRIL, MaterialNames.NICKEL, MaterialNames.STARSTEEL, + MaterialNames.STEEL, MaterialNames.IRON); + + private static final Set ARMOR = set(MaterialNames.ADAMANTINE, + MaterialNames.AQUARIUM, MaterialNames.BRASS, MaterialNames.BRONZE, + MaterialNames.COLDIRON, MaterialNames.COPPER, MaterialNames.CUPRONICKEL, + MaterialNames.ELECTRUM, MaterialNames.INVAR, MaterialNames.MITHRIL, + MaterialNames.NICKEL, MaterialNames.PLATINUM, MaterialNames.SILVER, + MaterialNames.STARSTEEL, MaterialNames.STEEL); + private static final Set PROTECTIVE = union(ARMOR, + set(MaterialNames.IRON, MaterialNames.GOLD, MaterialNames.DIAMOND)); + + private static final Set AMMUNITION = union(FULL_TOOLS, + set(MaterialNames.SILVER, MaterialNames.OBSIDIAN, MaterialNames.DIAMOND)); + + private static final Set GEARS = set(MaterialNames.ADAMANTINE, + MaterialNames.AQUARIUM, MaterialNames.BRASS, MaterialNames.BRONZE, + MaterialNames.COLDIRON, MaterialNames.COPPER, MaterialNames.CUPRONICKEL, + MaterialNames.INVAR, MaterialNames.MITHRIL, MaterialNames.NICKEL, + MaterialNames.STARSTEEL, MaterialNames.STEEL, MaterialNames.IRON, + MaterialNames.GOLD, MaterialNames.WOOD); + + private static final Set TOOLS = Collections.unmodifiableSet( + new LinkedHashSet<>(Arrays.asList(MaterialForm.AXE, MaterialForm.CRACKHAMMER, + MaterialForm.HOE, MaterialForm.PICKAXE, MaterialForm.SCYTHE, + MaterialForm.SHEARS, MaterialForm.SHOVEL, MaterialForm.SWORD))); + private static final Set ARMOR_FORMS = Collections.unmodifiableSet( + new LinkedHashSet<>(Arrays.asList(MaterialForm.BOOTS, MaterialForm.CHESTPLATE, + MaterialForm.HELMET, MaterialForm.LEGGINGS, MaterialForm.HORSE_ARMOR, + MaterialForm.SHIELD))); + private static final Set BUILDING_FORMS = Collections.unmodifiableSet( + new LinkedHashSet<>(Arrays.asList(MaterialForm.ANVIL, MaterialForm.BARS, + MaterialForm.BLOCK, MaterialForm.BOOKSHELF, MaterialForm.BUTTON, + MaterialForm.DOOR, MaterialForm.DOUBLE_SLAB, MaterialForm.FENCE, + MaterialForm.FENCE_GATE, MaterialForm.FLOWER_POT, MaterialForm.LADDER, + MaterialForm.LEVER, MaterialForm.PLATE, MaterialForm.PRESSURE_PLATE, + MaterialForm.SLAB, MaterialForm.STAIRS, MaterialForm.TRAPDOOR, + MaterialForm.TRIPWIRE_HOOK, MaterialForm.WALL))); + + private final ContentMode mode; + + private ContentPolicy(final ContentMode mode) { + this.mode = mode; + } + + public static ContentPolicy forMode(final ContentMode mode) { + return new ContentPolicy(mode == null ? ContentMode.HIGH_FANTASY : mode); + } + + public static ContentPolicy active() { + return forMode(com.mcmoddev.basemetals.util.BMeConfig.getActiveContentMode()); + } + + public ContentMode mode() { + return mode; + } + + public boolean allowsMaterial(final String material) { + return mode != ContentMode.REALISM || !MYTHICAL.contains(normalize(material)); + } + + public boolean allows(final String material, final MaterialForm form) { + final String name = normalize(material); + if (mode == ContentMode.HIGH_FANTASY || material == null || form == null) { + return true; + } + if (!allowsMaterial(name)) { + return false; + } + if (form == MaterialForm.OTHER) { + return !MaterialNames.MERCURY.equals(name); + } + if (form == MaterialForm.BOW || form == MaterialForm.CROSSBOW + || form == MaterialForm.FISHING_ROD) { + return false; + } + if (TOOLS.contains(form)) { + return allowsTool(name, form); + } + if (ARMOR_FORMS.contains(form)) { + return PROTECTIVE.contains(name); + } + if (form == MaterialForm.ARROW || form == MaterialForm.BOLT) { + return AMMUNITION.contains(name); + } + if (form == MaterialForm.GEAR) { + return GEARS.contains(name); + } + if (form == MaterialForm.ANVIL) { + return MaterialNames.STONE.equals(name) || MaterialNames.STEEL.equals(name) + || (mode == ContentMode.LOW_FANTASY && MaterialNames.ADAMANTINE.equals(name)); + } + if (MaterialNames.MERCURY.equals(name)) { + return form == MaterialForm.ORE || form == MaterialForm.POWDER + || form == MaterialForm.SMALLPOWDER || form == MaterialForm.FLUID + || (mode == ContentMode.LOW_FANTASY && form == MaterialForm.INGOT); + } + if (BUILDING_FORMS.contains(form)) { + return true; + } + return true; + } + + public boolean allows(final ItemStack stack) { + if (stack == null || stack.isEmpty() || stack.getItem().getRegistryName() == null) { + return true; + } + return allows(stack.getItem().getRegistryName()); + } + + public boolean allows(final ResourceLocation id) { + if (id == null || !BaseMetals.MODID.equals(id.getNamespace())) { + return true; + } + final String material = materialFromPath(id.getPath()); + if (material == null) { + return true; + } + MaterialForm form = MaterialForm.fromRegistryPath(id.getPath()); + if (form == MaterialForm.OTHER && id.getPath().equals(material)) { + form = MaterialForm.FLUID; + } + return allows(material, form); + } + + /** Resolves a recipe ID when a dynamic recipe has no representative output stack. */ + public boolean allowsRecipeId(final ResourceLocation recipeId) { + if (recipeId == null || !BaseMetals.MODID.equals(recipeId.getNamespace())) { + return true; + } + final String material = materialFromPath(recipeId.getPath()); + if (material == null) { + return true; + } + final String path = recipeId.getPath(); + String remainder = path.startsWith("double_" + material + "_") + ? path.substring(("double_" + material + "_").length()) + : path.equals(material) ? "" : path.substring((material + "_").length()); + MaterialForm form = MaterialForm.fromRegistryPath(path); + if (form == MaterialForm.OTHER) { + for (final MaterialForm candidate : MaterialForm.values()) { + final String token = candidate.name().toLowerCase(Locale.ROOT); + if (remainder.equals(token) || remainder.startsWith(token + "_")) { + form = candidate; + break; + } + } + } + return allows(material, form); + } + + public boolean defaultsOreEnabled(final String material) { + return mode != ContentMode.REALISM || !MYTHICAL.contains(normalize(material)); + } + + public static boolean isMythical(final String material) { + return MYTHICAL.contains(normalize(material)); + } + + public static String materialFromPath(final String registryPath) { + if (registryPath == null) { + return null; + } + final String path = registryPath.toLowerCase(Locale.ROOT); + for (final String material : MATERIALS) { + if (path.equals(material) || path.startsWith(material + "_") + || path.startsWith("double_" + material + "_")) { + return material; + } + } + return null; + } + + private boolean allowsTool(final String material, final MaterialForm form) { + if (FULL_TOOLS.contains(material)) { + return true; + } + if (MaterialNames.SILVER.equals(material)) { + return form == MaterialForm.SWORD; + } + if (MaterialNames.OBSIDIAN.equals(material)) { + return form == MaterialForm.AXE || form == MaterialForm.SWORD + || form == MaterialForm.SCYTHE; + } + if (MaterialNames.DIAMOND.equals(material)) { + return form == MaterialForm.CRACKHAMMER || form == MaterialForm.SCYTHE + || form == MaterialForm.SHEARS; + } + if (MaterialNames.STONE.equals(material)) { + return form == MaterialForm.CRACKHAMMER || form == MaterialForm.SCYTHE; + } + return MaterialNames.WOOD.equals(material) && form == MaterialForm.CRACKHAMMER; + } + + private static String normalize(final String material) { + return material == null ? "" : material.trim().toLowerCase(Locale.ROOT); + } + + private static Set set(final String... values) { + return Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(values))); + } + + private static Set union(final Set first, final Set second) { + final Set values = new LinkedHashSet<>(first); + values.addAll(second); + return Collections.unmodifiableSet(values); + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/content/MaterialForm.java b/src/main/java/com/mcmoddev/basemetals/content/MaterialForm.java new file mode 100644 index 00000000..1287ac53 --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/content/MaterialForm.java @@ -0,0 +1,92 @@ +package com.mcmoddev.basemetals.content; + +import java.util.Locale; + +/** Form families used by the content policy. Registry identities are never removed. */ +public enum MaterialForm { + ARROW, + AXE, + BLEND, + BOOTS, + BOLT, + BOW, + CHESTPLATE, + CRACKHAMMER, + CROSSBOW, + FISHING_ROD, + GEAR, + HELMET, + HOE, + HORSE_ARMOR, + INGOT, + LEGGINGS, + NUGGET, + PICKAXE, + POWDER, + ROD, + SCYTHE, + SHEARS, + SHIELD, + SHOVEL, + SMALLBLEND, + SMALLPOWDER, + SWORD, + CASING, + CLUMP, + CRUSHED, + CRUSHED_PURIFIED, + CRYSTAL, + DENSE_PLATE, + DIRTY_POWDER, + SHARD, + ANVIL, + BARS, + BLOCK, + BOOKSHELF, + BUTTON, + DOOR, + DOUBLE_SLAB, + FENCE, + FENCE_GATE, + FLOWER_POT, + LADDER, + LEVER, + PLATE, + PRESSURE_PLATE, + SLAB, + STAIRS, + TRAPDOOR, + TRIPWIRE_HOOK, + WALL, + ORE, + FLUID, + OTHER; + + /** Resolves the conventional suffix used by Base Metals and MMDLib registry IDs. */ + public static MaterialForm fromRegistryPath(final String registryPath) { + if (registryPath == null) { + return OTHER; + } + final String path = registryPath.toLowerCase(Locale.ROOT); + MaterialForm match = OTHER; + int longestMatch = -1; + for (final MaterialForm form : values()) { + if (form == OTHER || form == FLUID) { + continue; + } + final String suffix = registrySuffix(form); + if (path.endsWith("_" + suffix) && suffix.length() > longestMatch) { + match = form; + longestMatch = suffix.length(); + } + } + return match; + } + + private static String registrySuffix(final MaterialForm form) { + if (form == DIRTY_POWDER) { + return "powder_dirty"; + } + return form.name().toLowerCase(Locale.ROOT); + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/data/MaterialNames.java b/src/main/java/com/mcmoddev/basemetals/data/MaterialNames.java index 245ed3cb..d780881b 100755 --- a/src/main/java/com/mcmoddev/basemetals/data/MaterialNames.java +++ b/src/main/java/com/mcmoddev/basemetals/data/MaterialNames.java @@ -1,56 +1,48 @@ -package com.mcmoddev.basemetals.data; - -import com.mcmoddev.lib.data.SharedStrings; - -/** - *

Material Names:

- * This class contains references to commonly used material names.
- *
- * The Strings contained within this class are the String representations - * of common metals that can be available in Minecraft, other mods, and Base Metals.
- *
- * Refer to these Strings when referencing a particular metal type. - */ -public final class MaterialNames { - - public static final String ADAMANTINE = "adamantine"; - public static final String ANTIMONY = "antimony"; - public static final String AQUARIUM = "aquarium"; - public static final String BISMUTH = "bismuth"; - public static final String BRASS = "brass"; - public static final String BRONZE = "bronze"; - public static final String COAL = "coal"; - public static final String COLDIRON = "coldiron"; - public static final String COPPER = "copper"; - public static final String CHARCOAL = "charcoal"; - public static final String CUPRONICKEL = "cupronickel"; - public static final String DIAMOND = "diamond"; - public static final String ELECTRUM = "electrum"; - public static final String EMERALD = "emerald"; - public static final String ENDER = "ender"; - public static final String GOLD = "gold"; - public static final String INVAR = "invar"; - public static final String IRON = "iron"; - public static final String LAPIS = "lapis"; - public static final String LEAD = "lead"; - public static final String MERCURY = "mercury"; - public static final String MITHRIL = "mithril"; - public static final String NICKEL = "nickel"; - public static final String OBSIDIAN = "obsidian"; - public static final String PEWTER = "pewter"; - public static final String PLATINUM = "platinum"; - public static final String PRISMARINE = "prismarine"; - public static final String QUARTZ = "quartz"; - public static final String REDSTONE = "redstone"; - public static final String SILVER = "silver"; - public static final String STARSTEEL = "starsteel"; - public static final String STEEL = "steel"; - public static final String STONE = "stone"; - public static final String TIN = "tin"; - public static final String WOOD = "wood"; - public static final String ZINC = "zinc"; - - private MaterialNames() { - throw new IllegalAccessError(SharedStrings.NOT_INSTANTIABLE); - } -} +package com.mcmoddev.basemetals.data; + +import com.mcmoddev.lib.data.SharedStrings; + +/** Stable material identifiers shared with MMDLib and optional integrations. */ +public final class MaterialNames { + + public static final String ADAMANTINE = "adamantine"; + public static final String ANTIMONY = "antimony"; + public static final String AQUARIUM = "aquarium"; + public static final String BISMUTH = "bismuth"; + public static final String BRASS = "brass"; + public static final String BRONZE = "bronze"; + public static final String COAL = "coal"; + public static final String COLDIRON = "coldiron"; + public static final String COPPER = "copper"; + public static final String CHARCOAL = "charcoal"; + public static final String CUPRONICKEL = "cupronickel"; + public static final String DIAMOND = "diamond"; + public static final String ELECTRUM = "electrum"; + public static final String EMERALD = "emerald"; + public static final String ENDER = "ender"; + public static final String GOLD = "gold"; + public static final String INVAR = "invar"; + public static final String IRON = "iron"; + public static final String LAPIS = "lapis"; + public static final String LEAD = "lead"; + public static final String MERCURY = "mercury"; + public static final String MITHRIL = "mithril"; + public static final String NICKEL = "nickel"; + public static final String OBSIDIAN = "obsidian"; + public static final String PEWTER = "pewter"; + public static final String PLATINUM = "platinum"; + public static final String PRISMARINE = "prismarine"; + public static final String QUARTZ = "quartz"; + public static final String REDSTONE = "redstone"; + public static final String SILVER = "silver"; + public static final String STARSTEEL = "starsteel"; + public static final String STEEL = "steel"; + public static final String STONE = "stone"; + public static final String TIN = "tin"; + public static final String WOOD = "wood"; + public static final String ZINC = "zinc"; + + private MaterialNames() { + throw new IllegalAccessError(SharedStrings.NOT_INSTANTIABLE); + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/data/TraitNames.java b/src/main/java/com/mcmoddev/basemetals/data/TraitNames.java index 8dea5acf..559428d8 100644 --- a/src/main/java/com/mcmoddev/basemetals/data/TraitNames.java +++ b/src/main/java/com/mcmoddev/basemetals/data/TraitNames.java @@ -2,211 +2,28 @@ import com.mcmoddev.lib.data.SharedStrings; -/** - *

Trait Names:


- * These strings refer to TiC tool modifiers. - * All traits found in this class are used by Base Metals in some way. - *

- * - *

Modifiers added by Base Metals:

- *
    - *
  • Sparkly:
    - * {@link com.mcmoddev.lib.integration.plugins.tinkers.traits.TraitSparkly}
  • - *
  • Soft:
    - * {@link com.mcmoddev.lib.integration.plugins.tinkers.traits.TraitSoft}
  • - *
- * - * - *

Modifiers added by TiC:

- *
    - *
  • Enderference:
    - * {@link slimeknights.tconstruct.tools.traits.TraitEnderference}
  • - *
  • Jagged:
    - * {@link slimeknights.tconstruct.tools.traits.TraitJagged}
  • - *
  • holy:
    - * {@link slimeknights.tconstruct.tools.traits.TraitHoly}
  • - *
  • coldblooded:
    - * {@link slimeknights.tconstruct.tools.traits.TraitColdblooded}
  • - *
  • insatiable:
    - * {@link slimeknights.tconstruct.tools.traits.TraitInsatiable}
  • - *
  • aquadynamic:
    - * {@link slimeknights.tconstruct.tools.traits.TraitAquadynamic}
  • - *
  • dense:
    - * {@link slimeknights.tconstruct.tools.traits.TraitDense}
  • - *
  • freezing:
    - * {@link slimeknights.tconstruct.tools.traits.TraitFreezing}
  • - *
- * - *

Other Modifiers:

- * Other modifiers that can be found in the library of Base Metals but are not utilized by Base Metals:
- * If you are looking for the modifiers applicable to Modern Metals, please use the references below. - * - *

Modifiers added by Modern Metals:

- *
    - *
  • Heavy:
    - * {@link com.mcmoddev.lib.integration.plugins.tinkers.traits.TraitHeavy}
  • - *
  • Brittle:
    - * {@link com.mcmoddev.lib.integration.plugins.tinkers.traits.TraitBrittle}
  • - *
  • Toxic:
    - * {@link com.mcmoddev.lib.integration.plugins.tinkers.traits.TraitToxic}
  • - *
  • Radioactive:
    - * {@link com.mcmoddev.lib.integration.plugins.tinkers.traits.TraitRadioactive}
  • - *
  • Reactive:
    - * {@link com.mcmoddev.lib.integration.plugins.tinkers.traits.TraitReactive}
  • - *
- */ +/** Stable trait identifiers shared with Tinkers' Construct and Construct's Armory. */ public final class TraitNames { - //:: Base Metal Modifiers - /** - *

Sparkly Tool Modifier:

- * Name: sparkly - *
- * Desc: This modifier, when applied to tools, has an automatic durability repair effect. Heals the tool for - * 1 durability every 200 ticks. (10 seconds) - * - *
- * Modifier class: - * {@link com.mcmoddev.lib.integration.plugins.tinkers.traits.TraitSparkly} - */ + // Traits supplied by MMDLib for Base Metals materials. public static final String SPARKLY = "sparkly"; - - /** - *

Soft Tool Modifier:

- * Name: soft - *
- * Desc: This modifier, when applied to tools, increases the damage used by the tool when the tool is damaged by - * a factor of 1.25
(i.e. 1.25 more damage will be dealt to the tool's durability) - * - *
- * Modifier class: - * {@link com.mcmoddev.lib.integration.plugins.tinkers.traits.TraitSoft} - */ public static final String SOFT = "soft"; - //:: Tinkers Modifiers - /** - *

Enderference Tool Modifier:

- * Name: enderference - *
- * Desc: doc source and accreditation
- * Prevent an enderman from teleporting for 5 seconds after hitting it. - * - *
- * Modifier class: - * {@link slimeknights.tconstruct.tools.traits.TraitEnderference} - */ + // Traits supplied by Tinkers' Construct or Construct's Armory. public static final String ENDERFERENCE = "enderference"; - - /** - *

Jagged Tool Modifier:

- * Name: jagged - *
- * Desc: doc source and accreditation
- * Gains bonus damage when tool is damaged. The more damaged it is (difference, not percentage), the more damage it deals. - * Tool damage output is increased by:
log((maxDurability - durability) / 72d + 1d) * 2; - * - *
- * Modifier class: - * {@link slimeknights.tconstruct.tools.traits.TraitJagged} - */ public static final String JAGGED = "jagged"; - - /** - *

Holy Tool Modifier:

- * Name: holy - *
- * Desc: - * Damage of the tool is increased by 5 if target is an undead mob. - * - *
- * Modifier class: - * {@link slimeknights.tconstruct.tools.traits.TraitHoly} - */ public static final String HOLY = "holy"; - - /** - *

Coldblooded Tool Modifier:

- * Name: coldblooded - *
- * Desc: - * If the target of the tool is at full health, the damage dealt to the target is equivalent to the original - * damage dealt plus half of the original damage dealt. - * - *
- * Modifier class: - * {@link slimeknights.tconstruct.tools.traits.TraitColdblooded} - */ public static final String COLDBLOODED = "coldblooded"; - - /** - *

Insatiable Tool Modifier:

- * Name: insatiable - *
- * Desc: doc source and accreditation
- * Using the tool adds a level of insatiable for 15 seconds, limited to 10 levels. Increases speed and damage by (level / 3). - * - *
- * Modifier class: - * {@link slimeknights.tconstruct.tools.traits.TraitInsatiable} - */ public static final String INSATIABLE = "insatiable"; - - /** - *

Aquadynamic Tool Modifier:

- * Name: aquadynamic - *
- * Desc: - * Tool mining rate underwater is negated, and has the speeds of mining above water. - * Tool mining rate while raining is 1.6 that of the rain fall of the current biome that is being mined. - * I.E. mining speed is increased by the rainfall rate / 1.6 - * - *
- * Modifier class: - * {@link slimeknights.tconstruct.tools.traits.TraitAquadynamic} - */ public static final String AQUADYNAMIC = "aquadynamic"; - - /** - *

Dense Tool Modifier:

- * Name: dense - *
- * Desc: - * The chance for a tool to be damaged on use is changed to: - * (0.75f * (1f - durability / maxDurability))^3 - * - *
- * Modifier class: - * {@link slimeknights.tconstruct.tools.traits.TraitDense} - */ public static final String DENSE = "dense"; - - /** - *

Freezing Tool Modifier:

- * Name: freezing - *
- * Desc: - * Applies the slowness potion effect to the hit target of the tool. - * Each hit adds a level of slowness to the target up to a maximum of level 4 slowness. - * - *
- * Modifier class: - * {@link slimeknights.tconstruct.tools.traits.TraitFreezing} - */ public static final String FREEZING = "freezing"; - public static final String ICY = "icy"; - public static final String MALLEABLE = "malleable"; - public static final String MAGNETIC = "magnetic"; - public static final String MAGNETIC2 = "magnetic2"; - public static final String REACTIVE = "reactive"; - public static final String SHOCKING = "shocking"; - public static final String BRITTLE = "brittle"; private TraitNames() { diff --git a/src/main/java/com/mcmoddev/basemetals/init/Blocks.java b/src/main/java/com/mcmoddev/basemetals/init/Blocks.java index e6f046bb..ceca912b 100644 --- a/src/main/java/com/mcmoddev/basemetals/init/Blocks.java +++ b/src/main/java/com/mcmoddev/basemetals/init/Blocks.java @@ -21,12 +21,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.registries.IForgeRegistry; -/** - * This class initializes all blocks in Base Metals. - * - * @author Jasmine Iwanek - * - */ +/** Creates and registers Base Metals blocks. */ @Mod.EventBusSubscriber(modid=BaseMetals.MODID) public final class Blocks extends com.mcmoddev.lib.init.Blocks { @@ -34,9 +29,7 @@ private Blocks() { throw new IllegalAccessError(SharedStrings.NOT_INSTANTIABLE); } - /** - * - */ + /** Creates each material's block forms during MMDLib registration. */ @SubscribeEvent public static void init(final MMDLibRegisterBlocks event) { final List materials = Arrays.asList(MaterialNames.ADAMANTINE, @@ -92,11 +85,7 @@ private static void createMercury() { } } - /** - * Registers Blocks for this mod. - * - * @param event The Event. - */ + /** Adds the previously created blocks to Forge's block registry. */ @SubscribeEvent public static void registerBlocks(final RegistryEvent.Register event) { Materials.getMaterialsByMod(BaseMetals.MODID).stream() diff --git a/src/main/java/com/mcmoddev/basemetals/init/Fluids.java b/src/main/java/com/mcmoddev/basemetals/init/Fluids.java index 3e41b313..c53a705d 100644 --- a/src/main/java/com/mcmoddev/basemetals/init/Fluids.java +++ b/src/main/java/com/mcmoddev/basemetals/init/Fluids.java @@ -13,12 +13,7 @@ import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** - * This class initializes all fluids in Base Metals. - * - * @author Jasmine Iwanek - * - */ +/** Creates Base Metals fluids and their blocks. */ @Mod.EventBusSubscriber(modid=BaseMetals.MODID) public final class Fluids extends com.mcmoddev.lib.init.Fluids { @@ -26,9 +21,7 @@ private Fluids() { throw new IllegalAccessError(SharedStrings.NOT_INSTANTIABLE); } - /** - * - */ + /** Creates enabled molten-metal fluids during MMDLib registration. */ @SubscribeEvent public static void registerEvent(MMDLibRegisterFluids event) { final List materials = Arrays.asList(MaterialNames.ADAMANTINE, diff --git a/src/main/java/com/mcmoddev/basemetals/init/ItemGroups.java b/src/main/java/com/mcmoddev/basemetals/init/ItemGroups.java index 584413d4..0d08c24d 100644 --- a/src/main/java/com/mcmoddev/basemetals/init/ItemGroups.java +++ b/src/main/java/com/mcmoddev/basemetals/init/ItemGroups.java @@ -6,36 +6,16 @@ import com.mcmoddev.lib.init.Materials; import com.mcmoddev.lib.material.MMDMaterial; -/** - * This class initializes all item groups in Base Metals. - * - * @author Jasmine Iwanek - * - */ +/** Chooses representative icons for Base Metals creative tabs. */ public final class ItemGroups extends com.mcmoddev.lib.init.ItemGroups { -/* - private static final MMDCreativeTab blocksTab = addTab(SharedStrings.TAB_BLOCKS); - private static final MMDCreativeTab itemsTab = addTab(SharedStrings.TAB_ITEMS); - private static final MMDCreativeTab toolsTab = addTab(SharedStrings.TAB_TOOLS); - private static final MMDCreativeTab combatTab = addTab(SharedStrings.TAB_COMBAT); -*/ private ItemGroups() { throw new IllegalAccessError(SharedStrings.NOT_INSTANTIABLE); } - /** - * Initializer. - */ public static void init() { - // Blank Initializer } - /** - * Sets up icons for a CreativeTab. - * - * @param materialName - * Name of the preferred Material to use for Tab Icons - */ + /** Uses one material's block, gear, pickaxe, and sword as the four tab icons. */ public static void setupIcons(final String materialName) { if (Materials.hasMaterial(materialName)) { final MMDMaterial material = Materials.getMaterialByName(materialName); diff --git a/src/main/java/com/mcmoddev/basemetals/init/Items.java b/src/main/java/com/mcmoddev/basemetals/init/Items.java index c59214a8..a07365a0 100644 --- a/src/main/java/com/mcmoddev/basemetals/init/Items.java +++ b/src/main/java/com/mcmoddev/basemetals/init/Items.java @@ -3,17 +3,19 @@ import java.util.Arrays; import java.util.List; -import javax.annotation.Nonnull; - import com.google.common.collect.ImmutableList; import com.mcmoddev.basemetals.BaseMetals; import com.mcmoddev.basemetals.data.MaterialNames; +import com.mcmoddev.basemetals.items.ItemBaseMetalsArrow; +import com.mcmoddev.basemetals.items.ItemBaseMetalsBolt; +import com.mcmoddev.basemetals.items.ItemBaseMetalsBow; +import com.mcmoddev.basemetals.items.ItemBaseMetalsCrossbow; +import com.mcmoddev.basemetals.items.ItemBaseMetalsHoe; import com.mcmoddev.lib.data.Names; import com.mcmoddev.lib.data.SharedStrings; import com.mcmoddev.lib.events.MMDLibRegisterItems; import com.mcmoddev.lib.init.ItemGroups; import com.mcmoddev.lib.init.Materials; -import com.mcmoddev.lib.material.IMMDBurnableObject; import com.mcmoddev.lib.material.MMDMaterial; import com.mcmoddev.lib.util.Oredicts; @@ -25,12 +27,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.registries.IForgeRegistry; -/** - * This class initializes all items in Base Metals. - * - * @author Jasmine Iwanek - * - */ +/** Creates and registers Base Metals items. */ @Mod.EventBusSubscriber(modid=BaseMetals.MODID) public final class Items extends com.mcmoddev.lib.init.Items { @@ -38,9 +35,7 @@ private Items() { throw new IllegalAccessError(SharedStrings.NOT_INSTANTIABLE); } - /** - * - */ + /** Creates material forms before Forge opens the item registry. */ @SubscribeEvent public static void registerItems(MMDLibRegisterItems ev) { final List materials = Arrays.asList(MaterialNames.ADAMANTINE, @@ -53,7 +48,7 @@ public static void registerItems(MMDLibRegisterItems ev) { MaterialNames.SILVER, MaterialNames.STARSTEEL, MaterialNames.STEEL, MaterialNames.TIN, MaterialNames.ZINC); - // create and register modded stuffs + // These materials expose the extended processing forms used by integration mods. final List materialsModSupport = Arrays.asList(MaterialNames.ADAMANTINE, MaterialNames.ANTIMONY, MaterialNames.BISMUTH, MaterialNames.COLDIRON, MaterialNames.PLATINUM, MaterialNames.NICKEL, MaterialNames.STARSTEEL, @@ -71,18 +66,18 @@ public static void registerItems(MMDLibRegisterItems ev) { create(Names.SMALLBLEND, material); create(Names.SMALLPOWDER, material); - create(Names.ARROW, material); + createArrow(material); create(Names.AXE, material); - create(Names.BOLT, material); + createBolt(material); create(Names.BOOTS, material); - create(Names.BOW, material); + createBow(material); create(Names.CHESTPLATE, material); create(Names.CRACKHAMMER, material); - create(Names.CROSSBOW, material); + createCrossbow(material); create(Names.DOOR, material); create(Names.FISHING_ROD, material); create(Names.HELMET, material); - create(Names.HOE, material); + createHoe(material); create(Names.HORSE_ARMOR, material); create(Names.LEGGINGS, material); create(Names.PICKAXE, material); @@ -96,11 +91,6 @@ public static void registerItems(MMDLibRegisterItems ev) { create(Names.GEAR, material); }); - materials.stream() - .filter(Materials::hasMaterial) - .map(Materials::getMaterialByName) - .forEach(com.mcmoddev.basemetals.init.Items::setBurnTimes); - materialsModSupport.stream().filter(Materials::hasMaterial) .filter(materialName -> !Materials.getMaterialByName(materialName).isEmpty()) .forEach(materialName -> { @@ -139,35 +129,124 @@ public static void registerItems(MMDLibRegisterItems ev) { MinecraftForge.EVENT_BUS.register(Items.class); } - private static void setBurnTimes(@Nonnull final MMDMaterial material) { - if (material.hasItem(Names.NUGGET)) { - ((IMMDBurnableObject) material.getItem(Names.NUGGET)).setBurnTime(NUGGET_BURN_TIME); + /** Adds the previously created items to Forge's item registry. */ + @SubscribeEvent + public static void registerItems(final RegistryEvent.Register event) { + applyFishingRodDurability(); + + Materials.getAllMaterials() + .stream() + .filter(mat -> !mat.isVanilla()) + .forEach(mat -> regItems(event.getRegistry(), mat.getItems())); + + Oredicts.registerItemOreDictionaryEntries(); + Oredicts.registerBlockOreDictionaryEntries(); + } + + private static void applyFishingRodDurability() { + Materials.getAllMaterials().stream() + .filter(material -> material.hasItem(Names.FISHING_ROD)) + .forEach(material -> { + final Item fishingRod = material.getItem(Names.FISHING_ROD); + if (fishingRod.getRegistryName() != null + && BaseMetals.MODID.equals(fishingRod.getRegistryName().getNamespace())) { + fishingRod.setMaxDamage(material.getToolDurability()); + } + }); + } + + /** + * Creates a Base Metals-owned arrow whose material contributes to damage. + * + * @param material material used to construct the arrow + * @return the existing or newly created arrow, or {@code null} when disabled + */ + public static Item createArrow(final MMDMaterial material) { + if (material.hasItem(Names.ARROW)) { + return material.getItem(Names.ARROW); + } + if (!isNameEnabled(Names.ARROW)) { + return null; + } + return registerRangedItem(Names.ARROW, material, new ItemBaseMetalsArrow(material)); + } + + /** + * Creates a Base Metals-owned bolt whose material contributes to damage. + * + * @param material material used to construct the bolt + * @return the existing or newly created bolt, or {@code null} when disabled + */ + public static Item createBolt(final MMDMaterial material) { + if (material.hasItem(Names.BOLT)) { + return material.getItem(Names.BOLT); } + if (!isNameEnabled(Names.BOLT)) { + return null; + } + return registerRangedItem(Names.BOLT, material, new ItemBaseMetalsBolt(material)); + } - if (material.hasItem(Names.POWDER)) { - ((IMMDBurnableObject) material.getItem(Names.POWDER)).setBurnTime(INGOT_BURN_TIME); + /** + * Creates a Base Metals-owned bow whose material contributes to damage. + * + * @param material material used to construct the bow + * @return the existing or newly created bow, or {@code null} when disabled + */ + public static Item createBow(final MMDMaterial material) { + if (material.hasItem(Names.BOW)) { + return material.getItem(Names.BOW); + } + if (!isNameEnabled(Names.BOW)) { + return null; } + return registerRangedItem(Names.BOW, material, new ItemBaseMetalsBow(material)); + } - if (material.hasItem(Names.SMALLPOWDER)) { - ((IMMDBurnableObject) material.getItem(Names.SMALLPOWDER)).setBurnTime(NUGGET_BURN_TIME); + /** + * Creates a Base Metals-owned crossbow with the corrected server-side bolt + * firing behavior while preserving MMDLib's material and registry contracts. + * + * @param material material used to construct the crossbow + * @return the existing or newly created crossbow, or {@code null} when disabled + */ + public static Item createCrossbow(final MMDMaterial material) { + if (material.hasItem(Names.CROSSBOW)) { + return material.getItem(Names.CROSSBOW); + } + if (!isNameEnabled(Names.CROSSBOW)) { + return null; } + return registerRangedItem(Names.CROSSBOW, material, + new ItemBaseMetalsCrossbow(material)); } /** - * Registers Items for this mod. + * Creates a Base Metals-owned hoe which preserves ItemHoe's material-name + * contract for compatibility with other mods. * - * @param event The Event. + * @param material material used to construct the hoe + * @return the existing or newly created hoe, or {@code null} when disabled */ - @SubscribeEvent - public static void registerItems(final RegistryEvent.Register event) { - - Materials.getAllMaterials() - .stream() - .filter(mat -> !mat.isVanilla()) - .forEach(mat -> regItems(event.getRegistry(), mat.getItems())); + public static Item createHoe(final MMDMaterial material) { + if (material.hasItem(Names.HOE)) { + return material.getItem(Names.HOE); + } + if (!isNameEnabled(Names.HOE)) { + return null; + } + final Item registered = addItem(new ItemBaseMetalsHoe(material), + Names.HOE.toString(), material, ItemGroups.getTab(SharedStrings.TAB_TOOLS)); + material.addNewItem(Names.HOE, registered); + return registered; + } - Oredicts.registerItemOreDictionaryEntries(); - Oredicts.registerBlockOreDictionaryEntries(); + private static Item registerRangedItem(final Names name, final MMDMaterial material, + final Item item) { + final Item registered = addItem(item, name.toString(), material, + ItemGroups.getTab(SharedStrings.TAB_COMBAT)); + material.addNewItem(name, registered); + return registered; } private static void regItems(final IForgeRegistry registry, diff --git a/src/main/java/com/mcmoddev/basemetals/init/Materials.java b/src/main/java/com/mcmoddev/basemetals/init/Materials.java index 75c80577..1a6f599f 100644 --- a/src/main/java/com/mcmoddev/basemetals/init/Materials.java +++ b/src/main/java/com/mcmoddev/basemetals/init/Materials.java @@ -22,21 +22,14 @@ import net.minecraftforge.fluids.BlockFluidClassic; import net.minecraftforge.fluids.FluidRegistry; -/** - * This class initializes all of the materials in Base Metals. - * - * @author Jasmine Iwanek - * - */ +/** Defines Base Metals materials and their gameplay statistics. */ public final class Materials extends com.mcmoddev.lib.init.Materials { private Materials() { throw new IllegalAccessError(SharedStrings.NOT_INSTANTIABLE); } - /** - * - */ + /** Creates enabled materials when MMDLib opens its material registry. */ public static void init(final MMDLibRegisterMaterials event) { final List rareMaterials = Arrays.asList(MaterialNames.ADAMANTINE, MaterialNames.COLDIRON, MaterialNames.PLATINUM, MaterialNames.STARSTEEL); @@ -77,7 +70,7 @@ public BlockFluidClassic apply(String fluidName) { }); } - // Mod Materials + // Rare metals retain their historical blast resistance and dimension hints. if (hasMaterial(MaterialNames.ADAMANTINE)) { getMaterialByName(MaterialNames.ADAMANTINE).setBlastResistance(2000f).setSpawnSize(4) .setDefaultDimension(-1); diff --git a/src/main/java/com/mcmoddev/basemetals/init/Recipes.java b/src/main/java/com/mcmoddev/basemetals/init/Recipes.java index 48f799d8..9dea21eb 100644 --- a/src/main/java/com/mcmoddev/basemetals/init/Recipes.java +++ b/src/main/java/com/mcmoddev/basemetals/init/Recipes.java @@ -2,6 +2,7 @@ import com.mcmoddev.basemetals.BaseMetals; import com.mcmoddev.basemetals.data.MaterialNames; +import com.mcmoddev.basemetals.recipe.ContentAcquisitionFilters; import com.mcmoddev.lib.data.Names; import com.mcmoddev.lib.data.SharedStrings; import com.mcmoddev.lib.init.Materials; @@ -10,16 +11,13 @@ import net.minecraft.item.crafting.IRecipe; import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.oredict.OreDictionary; -/** - * - * @author Jasmine Iwanek - * - */ +/** Registers Base Metals crafting, furnace, and crusher recipes. */ @Mod.EventBusSubscriber(modid=BaseMetals.MODID) public final class Recipes extends com.mcmoddev.lib.init.Recipes { @@ -27,9 +25,7 @@ private Recipes() { throw new IllegalAccessError(SharedStrings.NOT_INSTANTIABLE); } - /** - * - */ + /** Registers the recipe handler on Forge's event bus. */ public static void init() { } @@ -39,7 +35,9 @@ private static void initModSpecificOredicts() { addAdditionalOredicts(adamantine, "Adamantite"); addAdditionalOredicts(adamantine, "Adamantium"); - addAdditionalOredicts(adamantine, "Adamant"); + if (!Loader.isModLoaded("taiga")) { + addAdditionalOredicts(adamantine, "Adamant"); + } } if (Materials.hasMaterial(MaterialNames.MERCURY)) { @@ -57,14 +55,11 @@ private static void initModSpecificOredicts() { } } - /** - * - * @param event - * The Event. - */ + /** Adds programmatic recipes and wraps restricted recipes with the content policy. */ @SubscribeEvent(priority=EventPriority.LOWEST) public static void registerRecipes(final RegistryEvent.Register event) { initModSpecificOredicts(); - register(event); + register(event); + ContentAcquisitionFilters.apply(event); } } diff --git a/src/main/java/com/mcmoddev/basemetals/init/VillagerTrades.java b/src/main/java/com/mcmoddev/basemetals/init/VillagerTrades.java index 48d0cf03..8d3b9d23 100644 --- a/src/main/java/com/mcmoddev/basemetals/init/VillagerTrades.java +++ b/src/main/java/com/mcmoddev/basemetals/init/VillagerTrades.java @@ -1,37 +1,133 @@ package com.mcmoddev.basemetals.init; +import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.content.ContentMode; +import com.mcmoddev.basemetals.content.ContentPolicy; +import com.mcmoddev.basemetals.content.MaterialForm; import com.mcmoddev.basemetals.data.MaterialNames; import com.mcmoddev.basemetals.util.VillagerTradeHelper; import com.mcmoddev.lib.data.ConfigKeys; +import com.mcmoddev.lib.data.MaterialStats; import com.mcmoddev.lib.data.Names; import com.mcmoddev.lib.data.SharedStrings; import com.mcmoddev.lib.init.Materials; import com.mcmoddev.lib.material.MMDMaterial; import net.minecraft.entity.passive.EntityVillager.ITradeList; +import net.minecraft.entity.passive.EntityVillager.ListEnchantedItemForEmeralds; +import net.minecraft.entity.passive.EntityVillager.PriceInfo; import net.minecraft.item.Item; -/** - * - * @author Jasmine Iwanek - * - */ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** Adds Base Metals offers to the vanilla smith careers. */ public final class VillagerTrades extends com.mcmoddev.lib.init.VillagerTrades { private VillagerTrades() { throw new IllegalAccessError(SharedStrings.NOT_INSTANTIABLE); } - /** - * - */ + /** Registers trades that are permitted by the startup content policy. */ public static void init() { if (com.mcmoddev.lib.util.Config.Options.isThingEnabled(ConfigKeys.VILLAGER_TRADES)) { - registerCommonTrades(); + if (ContentPolicy.active().mode() == ContentMode.HIGH_FANTASY) { + registerCommonTrades(); + } else { + registerRestrictedTrades(ContentPolicy.active()); + } registerModSpecificTrades(); } } + private static void registerRestrictedTrades(final ContentPolicy policy) { + final Map> enchanted = new HashMap<>(); + Materials.getMaterialsByMod(BaseMetals.MODID).stream() + .filter(material -> !material.isEmpty() && !material.isRare()) + .filter(VillagerTrades::hasAffordableTradeValue) + .forEach(material -> { + registerIngotTrades(material, policy); + if (material.getStat(MaterialStats.MAGICAFFINITY) > 5.0F) { + registerEnchantedTrades(material, policy, enchanted); + } + }); + commitTrades(enchanted); + } + + private static boolean hasAffordableTradeValue(final MMDMaterial material) { + final float value = tradeValue(material); + return emeraldPurchaseValue(value) < 65 && emeraldSaleValue(value) < 65; + } + + private static float tradeValue(final MMDMaterial material) { + return material.getStat(MaterialStats.HARDNESS) + + material.getStat(MaterialStats.STRENGTH) + + material.getStat(MaterialStats.MAGICAFFINITY) + + material.getToolHarvestLevel(); + } + + private static void registerIngotTrades(final MMDMaterial material, + final ContentPolicy policy) { + if (!material.hasItem(Names.INGOT) + || !policy.allows(material.getName(), MaterialForm.INGOT)) { + return; + } + final net.minecraft.item.ItemStack stack = material.getItemStack(Names.INGOT, 12); + if (stack.getItem() == net.minecraft.init.Items.EMERALD + || stack.getItem() == net.minecraft.init.Items.DIAMOND) { + return; + } + final int price = emeraldPurchaseValue(tradeValue(material)); + final int level = tradeLevel(tradeValue(material)); + final ITradeList[] trades = makePurchasePalette(price, stack); + VillagerTradeHelper.insertTrades(SMITH_RL, ARMOR_SMITH_ID, level, trades); + VillagerTradeHelper.insertTrades(SMITH_RL, WEAPON_SMITH_ID, level, trades); + VillagerTradeHelper.insertTrades(SMITH_RL, TOOL_SMITH_ID, level, trades); + } + + private static void registerEnchantedTrades(final MMDMaterial material, + final ContentPolicy policy, final Map> table) { + final int level = tradeLevel(tradeValue(material)); + final int basePrice = emeraldPurchaseValue(tradeValue(material)); + addEnchanted(table, WEAPON_SMITH | (level + 1), material, policy, + basePrice, (int) (material.getBaseAttackDamage() / 2) - 1, + Names.SWORD, Names.CROSSBOW, Names.BOW); + addEnchanted(table, ARMOR_SMITH | (level + 1), material, policy, + basePrice, (int) (material.getStat(MaterialStats.HARDNESS) / 2), + Names.HELMET, Names.CHESTPLATE, Names.LEGGINGS, Names.BOOTS); + addEnchanted(table, TOOL_SMITH | (level + 1), material, policy, + basePrice, 0, Names.AXE, Names.HOE, Names.SHOVEL, Names.PICKAXE); + addEnchanted(table, TOOL_SMITH | (level + 2), material, policy, + basePrice, 0, Names.CRACKHAMMER); + } + + private static void addEnchanted(final Map> table, + final int key, final MMDMaterial material, final ContentPolicy policy, + final int basePrice, final int priceModifier, final Names... forms) { + for (final Names name : Arrays.asList(forms)) { + if (!material.hasItem(name) + || !policy.allows(material.getName(), toForm(name))) { + continue; + } + table.computeIfAbsent(key, ignored -> new ArrayList<>()) + .addAll(Collections.singletonList(new ListEnchantedItemForEmeralds( + material.getItem(name), new PriceInfo(basePrice + 7 + priceModifier, + basePrice + 12 + priceModifier)))); + } + } + + private static MaterialForm toForm(final Names name) { + try { + return MaterialForm.valueOf(name.name()); + } catch (final IllegalArgumentException ignored) { + return MaterialForm.OTHER; + } + } + protected static void registerModSpecificTrades() { if (Materials.hasMaterial(MaterialNames.CHARCOAL)) { diff --git a/src/main/java/com/mcmoddev/basemetals/integration/orespawn/BaseMetalsOreSpawn.java b/src/main/java/com/mcmoddev/basemetals/integration/orespawn/BaseMetalsOreSpawn.java deleted file mode 100644 index 10635e8c..00000000 --- a/src/main/java/com/mcmoddev/basemetals/integration/orespawn/BaseMetalsOreSpawn.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.mcmoddev.basemetals.integration.orespawn; - -import com.mcmoddev.basemetals.BaseMetals; -import com.mcmoddev.lib.data.SharedStrings; -import com.mcmoddev.orespawn.api.os3.OS3API; -import com.mcmoddev.orespawn.api.plugin.IOreSpawnPlugin; -import com.mcmoddev.orespawn.api.plugin.OreSpawnPlugin; - -/** - * Declares Base Metals' packaged OreSpawn 3 data. - * - *

The plugin deliberately lives outside {@code com.mcmoddev.orespawn}. - * OreSpawn 3 releases sign that package, so putting an unsigned add-on class - * in it causes the JVM's package signer check to reject the integration.

- */ -@OreSpawnPlugin(modid = BaseMetals.MODID, resourcePath = SharedStrings.ORESPAWN_MODID) -public class BaseMetalsOreSpawn implements IOreSpawnPlugin { - - @Override - public void register(final OS3API apiInterface) { - // The annotation points OreSpawn at the packaged JSON configuration. - } -} diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeConstructsArmory.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeConstructsArmory.java index 5d0ec0a1..6b827d6e 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeConstructsArmory.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeConstructsArmory.java @@ -3,8 +3,12 @@ import c4.conarm.common.armor.traits.ArmorTraits; import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.content.ContentMode; +import com.mcmoddev.basemetals.content.ContentPolicy; +import com.mcmoddev.basemetals.content.MaterialForm; import com.mcmoddev.basemetals.data.MaterialNames; import com.mcmoddev.lib.integration.IIntegration; +import com.mcmoddev.lib.integration.IntegrationInitEvent; import com.mcmoddev.lib.integration.MMDPlugin; import com.mcmoddev.lib.integration.plugins.ConstructsArmory; import com.mcmoddev.lib.integration.plugins.armory.traits.MMDTraitsCA; @@ -17,6 +21,10 @@ import slimeknights.tconstruct.library.TinkerRegistry; import slimeknights.tconstruct.tools.TinkerTraits; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + import static com.mcmoddev.lib.integration.plugins.ConstructsArmory.*; @MMDPlugin(addonId = BaseMetals.MODID, pluginId = BMeConstructsArmory.PLUGIN_MODID, versions = BMeConstructsArmory.PLUGIN_MODID @@ -24,9 +32,10 @@ public final class BMeConstructsArmory implements IIntegration { public static final String PLUGIN_MODID = ConstructsArmory.PLUGIN_MODID; + private final List highFantasyMaterials = + new ArrayList<>(); public BMeConstructsArmory() { - // do nothing } @Override @@ -41,11 +50,28 @@ public void init() { @SubscribeEvent(priority = EventPriority.LOWEST) public void materialRegistration(MaterialRegistrationEvent ev) { if(Config.Options.isModEnabled(PLUGIN_MODID)){ - ev.getRegistry().getEntries().stream() - .map(ent -> ent.getValue()) - .forEach(mat -> { - TinkerRegistry.addMaterialStats(mat.getTinkerMaterial(), mat.getCoreStats(), mat.getPlatesStats(), mat.getTrimStats()); - switch (mat.getName()){ + if (ContentPolicy.active().mode() != ContentMode.HIGH_FANTASY) { + return; + } + highFantasyMaterials.clear(); + ev.getRegistry().getEntries().stream() + .map(ent -> ent.getValue()) + .forEach(highFantasyMaterials::add); + } + } + + /** Adds armor stats after ConArm has installed its default stat types. */ + @SubscribeEvent(priority = EventPriority.HIGHEST) + public void armorRegistration(final IntegrationInitEvent event) { + final Collection materials = + ContentPolicy.active().mode() == ContentMode.HIGH_FANTASY + ? highFantasyMaterials : BMeTinkersConstruct.restrictedMaterials(); + materials.stream() + .filter(mat -> ContentPolicy.active().allows(mat.getName(), MaterialForm.CHESTPLATE)) + .forEach(mat -> { + TinkerRegistry.addMaterialStats(mat.getTinkerMaterial(), mat.getCoreStats(), + mat.getPlatesStats(), mat.getTrimStats()); + switch (mat.getName()){ case MaterialNames.ADAMANTINE: addArmorTrait(mat.getTinkerMaterial(), ArmorTraits.vengeful, ArmorTraits.prideful); break; @@ -62,7 +88,8 @@ public void materialRegistration(MaterialRegistrationEvent ev) { addArmorTrait(mat.getTinkerMaterial(), MMDTraitsCA.icy); break; case MaterialNames.LEAD: - addArmorTrait(mat.getTinkerMaterial(), MMDTraitsCA.malleable); // Not being applied for some reason + // Keep the legacy trait request even though some ConArm versions ignore it. + addArmorTrait(mat.getTinkerMaterial(), MMDTraitsCA.malleable); break; case MaterialNames.MITHRIL: addArmorTrait(mat.getTinkerMaterial(), ArmorTraits.blessed); @@ -81,6 +108,5 @@ public void materialRegistration(MaterialRegistrationEvent ev) { addArmorTrait(mat.getTinkerMaterial(), MMDTraitsCA.reactive); } }); - } - } + } } diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeDenseOres.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeDenseOres.java index bb56978d..415f20a4 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeDenseOres.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeDenseOres.java @@ -4,6 +4,8 @@ import java.util.List; import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.content.ContentPolicy; +import com.mcmoddev.basemetals.content.MaterialForm; import com.mcmoddev.basemetals.data.MaterialNames; import com.mcmoddev.lib.init.Materials; import com.mcmoddev.lib.integration.IIntegration; @@ -24,11 +26,7 @@ public void init() { registerOres(); } - /** - * Register all ores that are currently known by the materials registry. - * - * @author Daniel Hazelton <dshadowwolf@gmail.com> - */ + /** Registers every policy-permitted Base Metals ore with Dense Ores. */ private static void registerOres() { final List materials = Arrays.asList(MaterialNames.ADAMANTINE, MaterialNames.ANTIMONY, MaterialNames.BISMUTH, MaterialNames.COLDIRON, @@ -38,6 +36,7 @@ private static void registerOres() { materials.stream().filter(Materials::hasMaterial) .filter(materialName -> !Materials.getMaterialByName(materialName).isEmpty()) + .filter(materialName -> ContentPolicy.active().allows(materialName, MaterialForm.ORE)) .forEach(materialName -> { String baseMaterial; switch (materialName) { diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeEnderIO.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeEnderIO.java index 7c3596d6..46bf6ac3 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeEnderIO.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeEnderIO.java @@ -7,6 +7,8 @@ import org.apache.commons.lang3.tuple.Triple; import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.content.ContentPolicy; +import com.mcmoddev.basemetals.content.MaterialForm; import com.mcmoddev.basemetals.data.MaterialNames; import com.mcmoddev.lib.init.Materials; import com.mcmoddev.lib.integration.IIntegration; @@ -16,17 +18,10 @@ import com.mcmoddev.lib.util.Config.Options; import com.mcmoddev.lib.util.Oredicts; -/** - * - * @author Jasmine Iwanek - * - */ +/** Registers Base Metals processing and alloy recipes with Ender IO. */ @MMDPlugin(addonId = BaseMetals.MODID, pluginId = BMeEnderIO.PLUGIN_MODID) public final class BMeEnderIO extends EnderIO implements IIntegration { - /** - * - */ @Override public void init() { if (!Options.isModEnabled(PLUGIN_MODID)) { @@ -43,13 +38,14 @@ public void init() { materials.stream().filter(Materials::hasMaterial) .filter(materialName -> !Materials.getMaterialByName(materialName).isEmpty()) + .filter(materialName -> ContentPolicy.active().allows(materialName, MaterialForm.POWDER)) .forEach(materialName -> addSagMillRecipe(materialName, 3600)); - addSagMillRecipe(MaterialNames.COPPER, 2, MaterialNames.GOLD, 1, 3600); - addSagMillRecipe(MaterialNames.LEAD, 2, MaterialNames.SILVER, 1, 3600); - addSagMillRecipe(MaterialNames.NICKEL, 2, MaterialNames.PLATINUM, 1, 3600); - addSagMillRecipe(MaterialNames.SILVER, 2, MaterialNames.LEAD, 1, 3600); - addSagMillRecipe(MaterialNames.IRON, 2, MaterialNames.NICKEL, 1, 3600); + addSagMillRecipeIfAllowed(MaterialNames.COPPER, 2, MaterialNames.GOLD, 1, 3600); + addSagMillRecipeIfAllowed(MaterialNames.LEAD, 2, MaterialNames.SILVER, 1, 3600); + addSagMillRecipeIfAllowed(MaterialNames.NICKEL, 2, MaterialNames.PLATINUM, 1, 3600); + addSagMillRecipeIfAllowed(MaterialNames.SILVER, 2, MaterialNames.LEAD, 1, 3600); + addSagMillRecipeIfAllowed(MaterialNames.IRON, 2, MaterialNames.NICKEL, 1, 3600); final String COPPER = "Copper"; final String IRON = "Iron"; @@ -78,6 +74,7 @@ public void init() { new Object[] { Oredicts.INGOT + IRON, 8, "itemCoal", 1 }))); alloys.stream() .filter(p -> Materials.hasMaterial(p.getRight().getLeft())) + .filter(p -> ContentPolicy.active().allows(p.getRight().getLeft(), MaterialForm.INGOT)) .forEach(p -> { final String name = p.getRight().getLeft(); final int count = p.getLeft(); @@ -89,4 +86,13 @@ public void init() { }); } + + private static void addSagMillRecipeIfAllowed(final String primary, final int primaryCount, + final String secondary, final int secondaryCount, final int energy) { + final ContentPolicy policy = ContentPolicy.active(); + if (policy.allows(primary, MaterialForm.POWDER) + && policy.allows(secondary, MaterialForm.POWDER)) { + addSagMillRecipe(primary, primaryCount, secondary, secondaryCount, energy); + } + } } diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeIC2.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeIC2.java index d909d6e5..9a80d53a 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeIC2.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeIC2.java @@ -4,6 +4,7 @@ import java.util.List; import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.content.ContentPolicy; import com.mcmoddev.basemetals.data.MaterialNames; import com.mcmoddev.lib.data.Names; import com.mcmoddev.lib.init.Materials; @@ -37,15 +38,13 @@ public void init() { MinecraftForge.EVENT_BUS.register(this); } - /** - * - * @param event The Event. - */ + /** Registers IC2 processing recipes after Forge has created the recipe registry. */ @SubscribeEvent public void mainInteraction(final RegistryEvent.Register event) { materials.stream().filter(Materials::hasMaterial) .filter(materialName -> !Materials.getMaterialByName(materialName).isEmpty()) + .filter(ContentPolicy.active()::allowsMaterial) .forEach(materialName -> { this.registerVanillaRecipes(materialName); this.addMaceratorRecipes(materialName); @@ -76,13 +75,12 @@ public void mainInteraction(final RegistryEvent.Register event) { MinecraftForge.EVENT_BUS.register(this); } - /** - * - */ + /** Adds the Forge Hammer conversions during integration initialization. */ @SubscribeEvent public void doHammerRecipes(final IntegrationInitEvent event) { materials.stream().filter(Materials::hasMaterial) .filter(materialName -> !Materials.getMaterialByName(materialName).isEmpty()) + .filter(ContentPolicy.active()::allowsMaterial) .forEach(this::addForgeHammerRecipe); } } diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeMekanism.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeMekanism.java index f8d11e1d..2be8b7e1 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeMekanism.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeMekanism.java @@ -6,6 +6,7 @@ import javax.annotation.Nonnull; import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.content.ContentPolicy; import com.mcmoddev.basemetals.data.MaterialNames; import com.mcmoddev.lib.data.Names; import com.mcmoddev.lib.init.Materials; @@ -37,6 +38,7 @@ public void init() { MinecraftForge.EVENT_BUS.register(this); materials.stream().filter(Materials::hasMaterial).filter(BMeMekanism::isMaterialNotEmpty) + .filter(ContentPolicy.active()::allowsMaterial) .forEach(Mekanism::addGassesForMaterial); } @@ -44,14 +46,12 @@ private static boolean isMaterialNotEmpty(@Nonnull final String materialName) { return !Materials.getMaterialByName(materialName).isEmpty(); } - /** - * - * @param event The Event. - */ + /** Registers Mekanism's ore-multiplication recipes. */ @SubscribeEvent public void regCallback(final RegistryEvent.Register event) { materials.stream().filter(Materials::hasMaterial).filter(BMeMekanism::isMaterialNotEmpty) + .filter(ContentPolicy.active()::allowsMaterial) .forEach(Mekanism::addOreMultiplicationRecipes); if (Materials.hasMaterial(MaterialNames.DIAMOND)) { diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeThermalExpansion.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeThermalExpansion.java index 3699d8ad..f80c5485 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeThermalExpansion.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeThermalExpansion.java @@ -4,6 +4,8 @@ import java.util.List; import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.content.ContentPolicy; +import com.mcmoddev.basemetals.content.MaterialForm; import com.mcmoddev.basemetals.data.MaterialNames; import com.mcmoddev.lib.data.Names; import com.mcmoddev.lib.init.Materials; @@ -32,10 +34,7 @@ public void init() { MinecraftForge.EVENT_BUS.register(this); } - /** - * - * @param event The Event. - */ + /** Registers Thermal processing and alloy recipes allowed by the content policy. */ @SubscribeEvent public void regShit(final RegistryEvent.Register event) { final List materials = Arrays.asList(MaterialNames.ADAMANTINE, @@ -47,11 +46,12 @@ public void regShit(final RegistryEvent.Register event) { materials.stream().filter(Materials::hasMaterial) .filter(materialName -> !Materials.getMaterialByName(materialName).isEmpty()) .forEach(materialName -> { - addFurnace(materialName); - addCrucible(materialName); - addPlatePress(materialName); - addPressStorage(materialName); - addPulverizer(materialName); + final ContentPolicy policy = ContentPolicy.active(); + if (policy.allows(materialName, MaterialForm.INGOT)) addFurnace(materialName); + if (policy.allows(materialName, MaterialForm.FLUID)) addCrucible(materialName); + if (policy.allows(materialName, MaterialForm.PLATE)) addPlatePress(materialName); + if (policy.allows(materialName, MaterialForm.BLOCK)) addPressStorage(materialName); + if (policy.allows(materialName, MaterialForm.POWDER)) addPulverizer(materialName); }); final MMDMaterial brass = Materials.getMaterialByName(MaterialNames.BRASS); @@ -62,21 +62,24 @@ public void regShit(final RegistryEvent.Register event) { final MMDMaterial tin = Materials.getMaterialByName(MaterialNames.TIN); final MMDMaterial bronze = Materials.getMaterialByName(MaterialNames.BRONZE); - if (hasMaterials(MaterialNames.COPPER, MaterialNames.ZINC, MaterialNames.BRASS) + if (ContentPolicy.active().allows(MaterialNames.BRASS, MaterialForm.INGOT) + && hasMaterials(MaterialNames.COPPER, MaterialNames.ZINC, MaterialNames.BRASS) && materialsHaveItems(Arrays.asList(MaterialNames.COPPER, MaterialNames.ZINC, MaterialNames.BRASS), Names.INGOT.toString())) { ThermalExpansionHelper.addSmelterRecipe(4000, copper.getItemStack(Names.INGOT, 2), zinc.getItemStack(Names.INGOT, 1), brass.getItemStack(Names.INGOT, 3)); } - if (hasMaterials(MaterialNames.COPPER, MaterialNames.NICKEL, MaterialNames.CUPRONICKEL) + if (ContentPolicy.active().allows(MaterialNames.CUPRONICKEL, MaterialForm.INGOT) + && hasMaterials(MaterialNames.COPPER, MaterialNames.NICKEL, MaterialNames.CUPRONICKEL) && materialsHaveItems(Arrays.asList(MaterialNames.COPPER, MaterialNames.NICKEL, MaterialNames.CUPRONICKEL), Names.INGOT.toString())) { ThermalExpansionHelper.addSmelterRecipe(4000, copper.getItemStack(Names.INGOT, 3), nickel.getItemStack(Names.INGOT, 1), cupronickel.getItemStack(Names.INGOT, 4)); } - if (hasMaterials(MaterialNames.COPPER, MaterialNames.TIN, MaterialNames.BRONZE) + if (ContentPolicy.active().allows(MaterialNames.BRONZE, MaterialForm.INGOT) + && hasMaterials(MaterialNames.COPPER, MaterialNames.TIN, MaterialNames.BRONZE) && materialsHaveItems(Arrays.asList(MaterialNames.COPPER, MaterialNames.TIN, MaterialNames.BRONZE), Names.INGOT.toString())) { ThermalExpansionHelper.addSmelterRecipe(4000, copper.getItemStack(Names.INGOT, 3), diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeTinkersConstruct.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeTinkersConstruct.java index 74a82026..6056514c 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeTinkersConstruct.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeTinkersConstruct.java @@ -1,12 +1,16 @@ package com.mcmoddev.basemetals.integration.plugins; import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.content.ContentMode; +import com.mcmoddev.basemetals.content.ContentPolicy; +import com.mcmoddev.basemetals.content.MaterialForm; import com.mcmoddev.basemetals.data.MaterialNames; import com.mcmoddev.basemetals.data.TraitNames; import com.mcmoddev.lib.data.Names; import com.mcmoddev.lib.init.Materials; import com.mcmoddev.lib.integration.IIntegration; import com.mcmoddev.lib.integration.IntegrationPostInitEvent; +import com.mcmoddev.lib.integration.IntegrationPreInitEvent; import com.mcmoddev.lib.integration.MMDPlugin; import com.mcmoddev.lib.integration.plugins.TinkersConstruct; import com.mcmoddev.lib.integration.plugins.tinkers.TinkerTraitLocation; @@ -31,30 +35,34 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import slimeknights.tconstruct.library.materials.Material; +import slimeknights.tconstruct.library.MaterialIntegration; +import slimeknights.tconstruct.library.TinkerRegistry; +import slimeknights.tconstruct.library.traits.ITrait; import slimeknights.tconstruct.smeltery.TinkerSmeltery; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import org.apache.commons.lang3.tuple.Pair; import static com.mcmoddev.lib.integration.plugins.TinkersConstruct.registerBasinCasting; import static com.mcmoddev.lib.integration.plugins.TinkersConstruct.registerTableCasting; -/** - * - * @author Jasmine Iwanek - * - */ +/** Registers Base Metals materials, casting, and alloys with Tinkers' Construct. */ @MMDPlugin(addonId = BaseMetals.MODID, pluginId = BMeTinkersConstruct.PLUGIN_MODID, versions = BMeTinkersConstruct.PLUGIN_MODID + "@[1.12.2-2.7.4.0,)") public class BMeTinkersConstruct implements IIntegration { public static final String PLUGIN_MODID = TinkersConstruct.PLUGIN_MODID; + private static final Map RESTRICTED_MATERIALS = + new LinkedHashMap<>(); public BMeTinkersConstruct() { - // do nothing } @Override @@ -77,6 +85,8 @@ public void registerMiscShit(RegistryEvent.Register ev) { .filter( b -> b.getFluid() != null) .forEach( base -> items.stream() + .filter(n -> ContentPolicy.active().allows(base.getName(), + MaterialForm.fromRegistryPath(base.getName() + "_" + n.toString()))) .filter( n -> base.hasItem(n)) .filter( nv -> base.getItem(nv).getRegistryName().getNamespace().equalsIgnoreCase(BaseMetals.MODID)) .map( name -> Pair.of(name.toString(), Integer.valueOf(CheeseMath.getIngotCount(base, base.getItemStack(name))))) @@ -86,11 +96,13 @@ public void registerMiscShit(RegistryEvent.Register ev) { @SubscribeEvent public void postInit(final IntegrationPostInitEvent event){ - if(Options.isMaterialEnabled(MaterialNames.PRISMARINE) && Options.isFluidEnabled(MaterialNames.PRISMARINE)) { + if (Options.isFluidEnabled(MaterialNames.PRISMARINE) + && isMaterialFluidEnabled(MaterialNames.PRISMARINE)) { registerPrismarineFullCasting(); } - // TODO Add a config option to enable/disable this - if(Options.isMaterialEnabled(MaterialNames.ENDER) && Options.isFluidEnabled(MaterialNames.ENDER)) { + // Ender casting follows the existing per-fluid switch, like prismarine above. + if (Options.isFluidEnabled(MaterialNames.ENDER) + && isMaterialFluidEnabled(MaterialNames.ENDER)) { registerEnderFullCasting(); } } @@ -115,6 +127,9 @@ private static void registerEnderFullCasting(){ @SubscribeEvent public void materialRegistration(MaterialRegistrationEvent ev) { + if (ContentPolicy.active().mode() != ContentMode.HIGH_FANTASY) { + return; + } registerMaterial(MaterialNames.ADAMANTINE, ev, TraitNames.COLDBLOODED, TraitNames.INSATIABLE); @@ -150,6 +165,108 @@ public void materialRegistration(MaterialRegistrationEvent ev) { TraitNames.REACTIVE); } + /** + * MMDLib's material wrapper unconditionally adds bow, bowstring, shaft and + * fletching statistics. Restricted modes therefore integrate their materials + * directly after MMDLib has finished, adding only policy-permitted stat families. + */ + @SubscribeEvent(priority = EventPriority.LOW) + public void restrictedMaterialRegistration(final IntegrationPreInitEvent event) { + if (ContentPolicy.active().mode() == ContentMode.HIGH_FANTASY) { + return; + } + RESTRICTED_MATERIALS.clear(); + registerRestrictedMaterial(MaterialNames.ADAMANTINE, + TraitNames.COLDBLOODED, TraitNames.INSATIABLE); + registerRestrictedMaterial(MaterialNames.ANTIMONY, TraitNames.BRITTLE); + registerRestrictedMaterial(MaterialNames.AQUARIUM, + TraitNames.AQUADYNAMIC, TinkerTraitLocation.HEAD, + TraitNames.JAGGED, TinkerTraitLocation.HEAD, TraitNames.AQUADYNAMIC); + registerRestrictedMaterial(MaterialNames.BISMUTH); + registerRestrictedMaterial(MaterialNames.BRASS, TraitNames.DENSE); + registerRestrictedMaterial(MaterialNames.COLDIRON, TraitNames.FREEZING); + registerRestrictedMaterial(MaterialNames.CUPRONICKEL); + registerRestrictedMaterial(MaterialNames.INVAR); + registerRestrictedMaterial(MaterialNames.LEAD, TraitNames.SOFT); + registerRestrictedMaterial(MaterialNames.MITHRIL, TraitNames.HOLY); + registerRestrictedMaterial(MaterialNames.NICKEL, + TraitNames.MAGNETIC, TinkerTraitLocation.HEAD, + TraitNames.SHOCKING, TinkerTraitLocation.HEAD, + TraitNames.MAGNETIC2, TraitNames.SHOCKING); + registerRestrictedMaterial(MaterialNames.PEWTER, TraitNames.SOFT); + registerRestrictedMaterial(MaterialNames.PLATINUM); + registerRestrictedMaterial(MaterialNames.STARSTEEL, + TraitNames.ENDERFERENCE, TinkerTraitLocation.HEAD, TraitNames.SPARKLY); + registerRestrictedMaterial(MaterialNames.TIN); + registerRestrictedMaterial(MaterialNames.ZINC, TraitNames.REACTIVE); + } + + private static void registerRestrictedMaterial(final String name, final Object... traits) { + final ContentPolicy policy = ContentPolicy.active(); + if (!Options.isMaterialEnabled(name) || !Materials.hasMaterial(name) + || !policy.allowsMaterial(name)) { + return; + } + final MMDMaterial base = Materials.getMaterialByName(name); + if (base.isEmpty()) { + return; + } + final TinkersMaterial helper = new TinkersMaterial(base) + .setCastable(true).setCraftable(false).setToolForge(true).create(); + final Material material = helper.getTinkerMaterial(); + final boolean toolParts = policy.allows(name, MaterialForm.PICKAXE); + final boolean ammunition = policy.allows(name, MaterialForm.ARROW); + if (toolParts) { + TinkerRegistry.addMaterialStats(material, helper.getHeadStats(), + helper.getHandleStats(), helper.getExtraStats()); + } + if (ammunition) { + TinkerRegistry.addMaterialStats(material, helper.getArrowShaftStats(), + helper.getFletchingStats()); + } + material.setCastable(true).setCraftable(false); + material.addCommonItems(base.getCapitalizedName()); + if (base.hasItem(Names.INGOT)) { + material.setRepresentativeItem(base.getItemStack(Names.INGOT)); + } + material.setVisible(); + material.setFluid(base.getFluid()); + addRestrictedTraits(material, traits); + final MaterialIntegration integration = TinkerRegistry.integrate(material, + base.getFluid(), base.getCapitalizedName()); + if (toolParts) { + integration.toolforge(); + } + if (TinkerRegistry.getMaterial(material.getIdentifier()) == Material.UNKNOWN) { + TinkerRegistry.addMaterial(material); + } + RESTRICTED_MATERIALS.put(name, helper); + } + + private static void addRestrictedTraits(final Material material, final Object... traits) { + int index = 0; + while (index < traits.length) { + TinkerTraitLocation location = TinkerTraitLocation.GENERAL; + Object entry = traits[index++]; + if (entry instanceof TinkerTraitLocation) { + location = (TinkerTraitLocation) entry; + entry = traits[index++]; + } + final ITrait trait = TinkerRegistry.getTrait(((String) entry).toLowerCase(Locale.US)); + if (trait != null) { + if (location == TinkerTraitLocation.GENERAL) { + material.addTrait(trait); + } else { + material.addTrait(trait, location.toString().toLowerCase(Locale.US)); + } + } + } + } + + static Collection restrictedMaterials() { + return Collections.unmodifiableCollection(RESTRICTED_MATERIALS.values()); + } + protected void registerMaterial(final String name, MaterialRegistrationEvent ev, final Object... traits){ registerMaterial(Options.isMaterialEnabled(name), name, ev, traits); } @@ -199,7 +316,8 @@ public void registerMeltings(TinkersExtraMeltingsEvent ev) { new ItemStack(Items.ENDER_PEARL)); } - if (isMaterialFluidEnabled(MaterialNames.MERCURY)) { + if (isMaterialFluidEnabled(MaterialNames.MERCURY) + && ContentPolicy.active().allows(MaterialNames.MERCURY, MaterialForm.INGOT)) { final MMDMaterial mercury = Materials.getMaterialByName(MaterialNames.MERCURY); TinkersConstruct.INSTANCE.addExtraMelting(FluidRegistry.getFluidStack(mercury.getName(), 144), mercury.getItemStack(Names.INGOT)); @@ -217,14 +335,16 @@ private boolean isMaterialFluidEnabled(String identifier){ } private boolean isValidAlloyMaterial(String identifier){ - return Materials.hasMaterial(identifier) && FluidRegistry.getFluid(identifier) != null; + return Materials.hasMaterial(identifier) && FluidRegistry.getFluid(identifier) != null + && ContentPolicy.active().allows(identifier, MaterialForm.FLUID); } @SubscribeEvent public void registerMyAlloys(TinkersAlloyRecipeEvent ev) { if (isValidAlloyMaterial(MaterialNames.AQUARIUM) && isValidAlloyMaterial(MaterialNames.COPPER) - && isValidAlloyMaterial(MaterialNames.ZINC)) { + && isValidAlloyMaterial(MaterialNames.ZINC) + && isValidAlloyMaterial(MaterialNames.PRISMARINE)) { final FluidStack copper = FluidRegistry.getFluidStack(MaterialNames.COPPER, 2); final FluidStack zinc = FluidRegistry.getFluidStack(MaterialNames.ZINC, 1); final FluidStack prismarine = FluidRegistry.getFluidStack(MaterialNames.PRISMARINE, 3); @@ -259,7 +379,7 @@ && isValidAlloyMaterial(MaterialNames.MERCURY)) { if (isValidAlloyMaterial(MaterialNames.PEWTER) && Materials.hasMaterial(MaterialNames.LEAD) && isValidAlloyMaterial(MaterialNames.COPPER) && isValidAlloyMaterial(MaterialNames.TIN)) { - // this makes what the "Worshipful Company of Pewterers" called "trifle" + // This 137:5:2 ratio is the historical pewter alloy known as "trifle". final FluidStack copper = FluidRegistry.getFluidStack(MaterialNames.COPPER, 2); final FluidStack tin = FluidRegistry.getFluidStack(MaterialNames.TIN, 137); final FluidStack lead = FluidRegistry.getFluidStack(MaterialNames.LEAD, 5); diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeVeinMiner.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeVeinMiner.java index bd1e2ec9..d8730ee5 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeVeinMiner.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeVeinMiner.java @@ -12,12 +12,7 @@ import com.mcmoddev.lib.integration.MMDPlugin; import com.mcmoddev.lib.util.Config.Options; -/** - * VeinMiner Integration Plugin. - * - * @author Jasmine Iwanek - * - */ +/** Registers Base Metals tools with VeinMiner when that integration is enabled. */ @MMDPlugin(addonId = BaseMetals.MODID, pluginId = BMeVeinMiner.PLUGIN_MODID) public final class BMeVeinMiner extends com.mcmoddev.lib.integration.plugins.VeinMiner implements IIntegration { diff --git a/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsArrow.java b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsArrow.java new file mode 100644 index 00000000..d78b490a --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsArrow.java @@ -0,0 +1,41 @@ +package com.mcmoddev.basemetals.items; + +import com.mcmoddev.lib.entity.EntityCustomArrow; +import com.mcmoddev.lib.item.ItemMMDArrow; +import com.mcmoddev.lib.material.MMDMaterial; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.projectile.EntityArrow; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +/** Base Metals arrow whose material contributes to projectile damage. */ +public final class ItemBaseMetalsArrow extends ItemMMDArrow { + + public ItemBaseMetalsArrow(final MMDMaterial material) { + super(material); + } + + @Override + public EntityCustomArrow createArrow(final World world, final ItemStack ammunition, + final EntityPlayer shooter) { + final ItemStack projectileAmmunition = ammunition.copy(); + projectileAmmunition.setCount(1); + final EntityCustomArrow projectile = super.createArrow( + world, projectileAmmunition, shooter); + MaterialRangedDamage.applyComponent(projectile, getMMDMaterial()); + return projectile; + } + + @Override + public EntityArrow createArrow(final World world, final ItemStack ammunition, + final EntityLivingBase shooter) { + if (shooter instanceof EntityPlayer) { + return createArrow(world, ammunition, (EntityPlayer) shooter); + } + final EntityArrow projectile = super.createArrow(world, ammunition, shooter); + MaterialRangedDamage.applyComponent(projectile, getMMDMaterial()); + return projectile; + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBolt.java b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBolt.java new file mode 100644 index 00000000..512422c8 --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBolt.java @@ -0,0 +1,25 @@ +package com.mcmoddev.basemetals.items; + +import com.mcmoddev.lib.entity.EntityCustomBolt; +import com.mcmoddev.lib.item.ItemMMDBolt; +import com.mcmoddev.lib.material.MMDMaterial; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +/** Base Metals bolt whose material contributes to projectile damage. */ +public final class ItemBaseMetalsBolt extends ItemMMDBolt { + + public ItemBaseMetalsBolt(final MMDMaterial material) { + super(material); + } + + @Override + public EntityCustomBolt createBolt(final World world, final ItemStack ammunition, + final EntityPlayer shooter) { + final EntityCustomBolt projectile = super.createBolt(world, ammunition, shooter); + MaterialRangedDamage.applyComponent(projectile, getMMDMaterial()); + return projectile; + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBow.java b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBow.java new file mode 100644 index 00000000..9350c1fc --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBow.java @@ -0,0 +1,120 @@ +package com.mcmoddev.basemetals.items; + +import javax.annotation.Nullable; + +import com.mcmoddev.lib.item.ItemMMDBow; +import com.mcmoddev.lib.material.MMDMaterial; + +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.projectile.EntityArrow; +import net.minecraft.init.Enchantments; +import net.minecraft.init.Items; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.ItemArrow; +import net.minecraft.item.ItemStack; +import net.minecraft.stats.StatList; +import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundCategory; +import net.minecraft.world.World; +import net.minecraftforge.event.ForgeEventFactory; + +/** Base Metals bow whose material contributes to projectile damage. */ +public final class ItemBaseMetalsBow extends ItemMMDBow { + + public ItemBaseMetalsBow(final MMDMaterial material) { + super(material); + } + + @Override + public void onPlayerStoppedUsing(final ItemStack bow, final World world, + final EntityLivingBase user, final int timeLeft) { + if (!(user instanceof EntityPlayer)) { + return; + } + + final EntityPlayer player = (EntityPlayer) user; + final boolean hasInfiniteAmmo = player.capabilities.isCreativeMode + || EnchantmentHelper.getEnchantmentLevel(Enchantments.INFINITY, bow) > 0; + ItemStack ammunition = findArrow(player); + int charge = this.getMaxItemUseDuration(bow) - timeLeft; + charge = ForgeEventFactory.onArrowLoose(bow, world, player, charge, + !ammunition.isEmpty() || hasInfiniteAmmo); + if (charge < 0 || ammunition.isEmpty() && !hasInfiniteAmmo) { + return; + } + + if (ammunition.isEmpty()) { + ammunition = new ItemStack(Items.ARROW); + } + + final float velocity = getArrowVelocity(charge); + if (velocity < 0.1F) { + return; + } + + final ItemArrow arrowItem = ammunition.getItem() instanceof ItemArrow + ? (ItemArrow) ammunition.getItem() : (ItemArrow) Items.ARROW; + final boolean infiniteShot = player.capabilities.isCreativeMode + || arrowItem.isInfinite(ammunition, bow, player); + if (!world.isRemote) { + final EntityArrow projectile = arrowItem.createArrow(world, ammunition, player); + MaterialRangedDamage.applyComponent(projectile, getMMDMaterial()); + projectile.shoot(player, player.rotationPitch, player.rotationYaw, 0.0F, + velocity * 3.0F, 1.0F); + if (velocity == 1.0F) { + projectile.setIsCritical(true); + } + + final int power = EnchantmentHelper.getEnchantmentLevel(Enchantments.POWER, bow); + if (power > 0) { + projectile.setDamage(projectile.getDamage() + power * 0.5D + 0.5D); + } + final int punch = EnchantmentHelper.getEnchantmentLevel(Enchantments.PUNCH, bow); + if (punch > 0) { + projectile.setKnockbackStrength(punch); + } + if (EnchantmentHelper.getEnchantmentLevel(Enchantments.FLAME, bow) > 0) { + projectile.setFire(100); + } + + bow.damageItem(1, player); + if (infiniteShot) { + projectile.pickupStatus = EntityArrow.PickupStatus.CREATIVE_ONLY; + } + world.spawnEntity(projectile); + } + + world.playSound(null, player.posX, player.posY, player.posZ, + SoundEvents.ENTITY_ARROW_SHOOT, SoundCategory.PLAYERS, 1.0F, + 1.0F / (itemRand.nextFloat() * 0.4F + 1.2F) + velocity * 0.5F); + if (!infiniteShot) { + ammunition.shrink(1); + if (ammunition.isEmpty()) { + player.inventory.deleteStack(ammunition); + } + } + player.addStat(StatList.getObjectUseStats(this)); + } + + private static ItemStack findArrow(final EntityPlayer player) { + if (isArrowStack(player.getHeldItem(EnumHand.OFF_HAND))) { + return player.getHeldItem(EnumHand.OFF_HAND); + } + if (isArrowStack(player.getHeldItem(EnumHand.MAIN_HAND))) { + return player.getHeldItem(EnumHand.MAIN_HAND); + } + for (int slot = 0; slot < player.inventory.getSizeInventory(); slot++) { + final ItemStack stack = player.inventory.getStackInSlot(slot); + if (isArrowStack(stack)) { + return stack; + } + } + return ItemStack.EMPTY; + } + + private static boolean isArrowStack(@Nullable final ItemStack stack) { + return stack != null && !stack.isEmpty() && stack.getItem() instanceof ItemArrow; + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsCrossbow.java b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsCrossbow.java new file mode 100644 index 00000000..2fe07b11 --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsCrossbow.java @@ -0,0 +1,140 @@ +package com.mcmoddev.basemetals.items; + +import javax.annotation.Nullable; + +import com.mcmoddev.basemetals.data.MaterialNames; +import com.mcmoddev.lib.data.Names; +import com.mcmoddev.lib.entity.EntityCustomBolt; +import com.mcmoddev.lib.init.Materials; +import com.mcmoddev.lib.item.ItemBolt; +import com.mcmoddev.lib.item.ItemMMDCrossbow; +import com.mcmoddev.lib.material.MMDMaterial; + +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Enchantments; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.ItemStack; +import net.minecraft.stats.StatList; +import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundCategory; +import net.minecraft.world.World; +import net.minecraftforge.event.ForgeEventFactory; + +/** + * Base Metals' 1.12 crossbow implementation. + * + *

MMDLib 1.0.0-rc2 creates bolts on the client, leaving the server with no + * projectile to resolve impacts or damage. This retains the MMDLib item and + * ammunition contracts while restoring the server-authoritative firing path + * used by Base Metals 1.10 and later ports.

+ */ +public final class ItemBaseMetalsCrossbow extends ItemMMDCrossbow { + + public ItemBaseMetalsCrossbow(final MMDMaterial material) { + super(material); + } + + @Override + public void onPlayerStoppedUsing(final ItemStack crossbow, final World world, + final EntityLivingBase user, final int timeLeft) { + if (!(user instanceof EntityPlayer)) { + return; + } + + final EntityPlayer player = (EntityPlayer) user; + final boolean hasInfiniteAmmo = player.capabilities.isCreativeMode + || EnchantmentHelper.getEnchantmentLevel(Enchantments.INFINITY, crossbow) > 0; + ItemStack ammunition = findBolt(player); + int charge = this.getMaxItemUseDuration(crossbow) - timeLeft; + charge = ForgeEventFactory.onArrowLoose(crossbow, world, player, charge, + !ammunition.isEmpty() || hasInfiniteAmmo); + if (charge < 0 || ammunition.isEmpty() && !hasInfiniteAmmo) { + return; + } + + if (ammunition.isEmpty()) { + ammunition = defaultBolt(); + if (ammunition.isEmpty()) { + return; + } + } + + final float velocity = getArrowVelocity(charge); + if (velocity < 0.1F) { + return; + } + + final ItemBolt boltItem = (ItemBolt) ammunition.getItem(); + final boolean infiniteShot = player.capabilities.isCreativeMode + || boltItem.isInfinite(ammunition, crossbow, player); + if (!world.isRemote) { + final ItemStack projectileAmmunition = ammunition.copy(); + projectileAmmunition.setCount(1); + final EntityCustomBolt projectile = boltItem.createBolt( + world, projectileAmmunition, player); + MaterialRangedDamage.applyComponent(projectile, getMMDMaterial()); + projectile.shoot(player, player.rotationPitch, player.rotationYaw, 0.0F, + velocity * 3.0F, 1.0F); + if (velocity == 1.0F) { + projectile.setIsCritical(true); + } + + final int power = EnchantmentHelper.getEnchantmentLevel(Enchantments.POWER, crossbow); + if (power > 0) { + projectile.setDamage(projectile.getDamage() + power * 0.5D + 0.5D); + } + final int punch = EnchantmentHelper.getEnchantmentLevel(Enchantments.PUNCH, crossbow); + if (punch > 0) { + projectile.setKnockbackStrength(punch); + } + if (EnchantmentHelper.getEnchantmentLevel(Enchantments.FLAME, crossbow) > 0) { + projectile.setFire(100); + } + + crossbow.damageItem(1, player); + if (infiniteShot) { + projectile.pickupStatus = EntityCustomBolt.PickupStatus.CREATIVE_ONLY; + } + world.spawnEntity(projectile); + } + + world.playSound(null, player.posX, player.posY, player.posZ, + SoundEvents.ENTITY_ARROW_SHOOT, SoundCategory.PLAYERS, 1.0F, + 1.0F / (itemRand.nextFloat() * 0.4F + 1.2F) + velocity * 0.5F); + if (!infiniteShot) { + ammunition.shrink(1); + if (ammunition.isEmpty()) { + player.inventory.deleteStack(ammunition); + } + } + player.addStat(StatList.getObjectUseStats(this)); + } + + private static ItemStack defaultBolt() { + final MMDMaterial iron = Materials.getMaterialByName(MaterialNames.IRON); + return iron.isEmpty() || !iron.hasItem(Names.BOLT) + ? ItemStack.EMPTY : new ItemStack(iron.getItem(Names.BOLT)); + } + + private static ItemStack findBolt(final EntityPlayer player) { + if (isBoltStack(player.getHeldItem(EnumHand.OFF_HAND))) { + return player.getHeldItem(EnumHand.OFF_HAND); + } + if (isBoltStack(player.getHeldItem(EnumHand.MAIN_HAND))) { + return player.getHeldItem(EnumHand.MAIN_HAND); + } + for (int slot = 0; slot < player.inventory.getSizeInventory(); slot++) { + final ItemStack stack = player.inventory.getStackInSlot(slot); + if (isBoltStack(stack)) { + return stack; + } + } + return ItemStack.EMPTY; + } + + private static boolean isBoltStack(@Nullable final ItemStack stack) { + return stack != null && !stack.isEmpty() && stack.getItem() instanceof ItemBolt; + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsHoe.java b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsHoe.java new file mode 100644 index 00000000..8427df3e --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsHoe.java @@ -0,0 +1,25 @@ +package com.mcmoddev.basemetals.items; + +import com.mcmoddev.lib.init.Materials; +import com.mcmoddev.lib.item.ItemMMDHoe; +import com.mcmoddev.lib.material.MMDMaterial; + +/** + * Base Metals hoe which exposes the real Forge tool-material name. + * + *

{@link net.minecraft.item.ItemHoe#getMaterialName()} is expected to return + * the backing {@link net.minecraft.item.Item.ToolMaterial} enum constant. The + * MMDLib implementation instead returns the lower-case material identifier, + * which breaks consumers that use the vanilla contract.

+ */ +public final class ItemBaseMetalsHoe extends ItemMMDHoe { + + public ItemBaseMetalsHoe(final MMDMaterial material) { + super(material); + } + + @Override + public String getMaterialName() { + return Materials.getToolMaterialFor(getMMDMaterial()).toString(); + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/items/MaterialRangedDamage.java b/src/main/java/com/mcmoddev/basemetals/items/MaterialRangedDamage.java new file mode 100644 index 00000000..5fb5cfe2 --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/items/MaterialRangedDamage.java @@ -0,0 +1,29 @@ +package com.mcmoddev.basemetals.items; + +import com.mcmoddev.lib.material.MMDMaterial; + +import net.minecraft.entity.projectile.EntityArrow; + +/** Shared material contribution used by Base Metals ranged weapons. */ +final class MaterialRangedDamage { + + private static final double NEUTRAL_COMPONENT_DAMAGE = 1.0D; + private static final double MINIMUM_PROJECTILE_DAMAGE = 0.1D; + + private MaterialRangedDamage() { + throw new IllegalAccessError("Not instantiable"); + } + + /** + * Replaces one vanilla-neutral launcher or ammunition contribution with the + * supplied material's established base attack damage. + * + * @param projectile projectile whose base damage is being composed + * @param material launcher or ammunition material + */ + static void applyComponent(final EntityArrow projectile, final MMDMaterial material) { + final double adjustedDamage = projectile.getDamage() + - NEUTRAL_COMPONENT_DAMAGE + material.getBaseAttackDamage(); + projectile.setDamage(Math.max(MINIMUM_PROJECTILE_DAMAGE, adjustedDamage)); + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/loot/ContentModeLootCondition.java b/src/main/java/com/mcmoddev/basemetals/loot/ContentModeLootCondition.java new file mode 100644 index 00000000..e09b74e0 --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/loot/ContentModeLootCondition.java @@ -0,0 +1,57 @@ +package com.mcmoddev.basemetals.loot; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.content.ContentPolicy; +import net.minecraft.util.JsonUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.storage.loot.LootContext; +import net.minecraft.world.storage.loot.conditions.LootCondition; +import net.minecraft.world.storage.loot.conditions.LootConditionManager; + +import java.util.Random; + +/** Hides Base Metals-owned auxiliary loot entries disallowed by the startup policy. */ +public final class ContentModeLootCondition implements LootCondition { + public static final ResourceLocation ID = new ResourceLocation(BaseMetals.MODID, "content_policy"); + private static boolean registered; + + private final ResourceLocation item; + + ContentModeLootCondition(final ResourceLocation item) { + this.item = item; + } + + public static synchronized void register() { + if (!registered) { + LootConditionManager.registerCondition(new Serializer()); + registered = true; + } + } + + @Override + public boolean testCondition(final Random random, final LootContext context) { + return ContentPolicy.active().allows(item); + } + + public static final class Serializer extends LootCondition.Serializer { + public Serializer() { + super(ID, ContentModeLootCondition.class); + } + + @Override + public void serialize(final JsonObject json, final ContentModeLootCondition value, + final JsonSerializationContext context) { + json.addProperty("item", value.item.toString()); + } + + @Override + public ContentModeLootCondition deserialize(final JsonObject json, + final JsonDeserializationContext context) { + return new ContentModeLootCondition(new ResourceLocation( + JsonUtils.getString(json, "item"))); + } + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/network/ClientContentModeConnectionHandler.java b/src/main/java/com/mcmoddev/basemetals/network/ClientContentModeConnectionHandler.java new file mode 100644 index 00000000..924a3a08 --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/network/ClientContentModeConnectionHandler.java @@ -0,0 +1,12 @@ +package com.mcmoddev.basemetals.network; + +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.network.FMLNetworkEvent; + +/** Sends the effective mode after Forge establishes the modded connection. */ +public final class ClientContentModeConnectionHandler { + @SubscribeEvent + public void connected(final FMLNetworkEvent.ClientConnectedToServerEvent event) { + ContentModeNetwork.sendClientMode(); + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/network/ContentModeMessage.java b/src/main/java/com/mcmoddev/basemetals/network/ContentModeMessage.java new file mode 100644 index 00000000..ccd11643 --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/network/ContentModeMessage.java @@ -0,0 +1,36 @@ +package com.mcmoddev.basemetals.network; + +import com.mcmoddev.basemetals.content.ContentMode; +import io.netty.buffer.ByteBuf; +import net.minecraftforge.fml.common.network.ByteBufUtils; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; + +/** Client declaration of its effective, startup-latched content mode. */ +public final class ContentModeMessage implements IMessage { + private String serializedMode; + + public ContentModeMessage() { + } + + ContentModeMessage(final ContentMode mode) { + serializedMode = mode.serializedName(); + } + + ContentMode mode() { + return ContentMode.fromSerializedName(serializedMode); + } + + boolean hasValidMode() { + return ContentMode.isValidSerializedName(serializedMode); + } + + @Override + public void fromBytes(final ByteBuf buffer) { + serializedMode = ByteBufUtils.readUTF8String(buffer); + } + + @Override + public void toBytes(final ByteBuf buffer) { + ByteBufUtils.writeUTF8String(buffer, serializedMode); + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/network/ContentModeNetwork.java b/src/main/java/com/mcmoddev/basemetals/network/ContentModeNetwork.java new file mode 100644 index 00000000..f9d05dfb --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/network/ContentModeNetwork.java @@ -0,0 +1,59 @@ +package com.mcmoddev.basemetals.network; + +import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.content.ContentMode; +import com.mcmoddev.basemetals.util.BMeConfig; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.util.text.TextComponentString; +import net.minecraftforge.fml.common.network.NetworkRegistry; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; +import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper; +import net.minecraftforge.fml.relauncher.Side; + +/** Stable network contract that prevents client/server recipe-policy disagreement. */ +public final class ContentModeNetwork { + private static final SimpleNetworkWrapper CHANNEL = + NetworkRegistry.INSTANCE.newSimpleChannel("bm_content_mode"); + private static boolean initialized; + + private ContentModeNetwork() { + } + + public static synchronized void init() { + if (!initialized) { + CHANNEL.registerMessage(ServerHandler.class, ContentModeMessage.class, 0, Side.SERVER); + initialized = true; + } + } + + public static void sendClientMode() { + CHANNEL.sendToServer(new ContentModeMessage(BMeConfig.getActiveContentMode())); + } + + public static boolean modesMatch(final ContentMode client, final ContentMode server) { + return client == server; + } + + public static final class ServerHandler + implements IMessageHandler { + @Override + public IMessage onMessage(final ContentModeMessage message, final MessageContext context) { + final EntityPlayerMP player = context.getServerHandler().player; + player.getServerWorld().addScheduledTask(() -> { + final ContentMode serverMode = BMeConfig.getActiveContentMode(); + if (!message.hasValidMode() || !modesMatch(message.mode(), serverMode)) { + final String clientName = message.hasValidMode() + ? message.mode().serializedName() : "invalid"; + final String reason = "Base Metals content mode mismatch: server uses '" + + serverMode.serializedName() + "' but client uses '" + clientName + + "'. Set General/contentMode to the same value and restart Minecraft."; + BaseMetals.logger.warn("Rejecting {}: {}", player.getName(), reason); + player.connection.disconnect(new TextComponentString(reason)); + } + }); + return null; + } + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/properties/AdamantineProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/AdamantineProperty.java index eda3bb89..544e3bb2 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/AdamantineProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/AdamantineProperty.java @@ -1,65 +1,61 @@ -package com.mcmoddev.basemetals.properties; - -import com.mcmoddev.basemetals.data.MaterialNames; -import com.mcmoddev.lib.init.Materials; -import com.mcmoddev.lib.material.IMMDObject; -import com.mcmoddev.lib.material.MMDMaterial; - -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.MobEffects; -import net.minecraft.item.ItemStack; -import net.minecraft.potion.PotionEffect; - -public class AdamantineProperty extends BMEPropertyBase { - @Override - public void apply(ItemStack stack) { - if(hasEffect(stack)) { - // only apply if there is an effect - // we should always double check here :) - } - } - - @Override - public void apply(ItemStack stack, EntityPlayer player) { - if(hasEffect(stack, player)) { - final int level = countArmorPieces(Materials.getMaterialByName(MaterialNames.ADAMANTINE), player) / 2; - if (level == 0) { - return; - } - if (level > 0) { - final PotionEffect protection = new PotionEffect(MobEffects.RESISTANCE, EFFECT_DURATION, - level - 1, false, false); - player.addPotionEffect(protection); - } - } - } - - @Override - public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { - apply(stack, (EntityPlayer)ent); - } - } - - @Override - public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack - } - - @Override - public boolean hasEffect(ItemStack stack, EntityPlayer player) { - MMDMaterial mat = Materials.getMaterialByName(MaterialNames.ADAMANTINE); - boolean rv = (stackIsArmorMaterial(stack, mat) - && ((stack.getItem() instanceof IMMDObject) && - (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && - (countArmorPieces(Materials.getMaterialByName(MaterialNames.ADAMANTINE),player) > 0); - - return rv; - } - - @Override - public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; - } -} +package com.mcmoddev.basemetals.properties; + +import com.mcmoddev.basemetals.data.MaterialNames; +import com.mcmoddev.lib.init.Materials; +import com.mcmoddev.lib.material.IMMDObject; +import com.mcmoddev.lib.material.MMDMaterial; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.PotionEffect; + +public class AdamantineProperty extends BMEPropertyBase { + @Override + public void apply(ItemStack stack) { + } + + @Override + public void apply(ItemStack stack, EntityPlayer player) { + if(hasEffect(stack, player)) { + final int level = countArmorPieces(Materials.getMaterialByName(MaterialNames.ADAMANTINE), player) / 2; + if (level == 0) { + return; + } + if (level > 0) { + final PotionEffect protection = new PotionEffect(MobEffects.RESISTANCE, EFFECT_DURATION, + level - 1, false, false); + player.addPotionEffect(protection); + } + } + } + + @Override + public void apply(ItemStack stack, EntityLivingBase ent) { + if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { + apply(stack, (EntityPlayer)ent); + } + } + + @Override + public boolean hasEffect(ItemStack stack) { + return false; // no effect for just the stack + } + + @Override + public boolean hasEffect(ItemStack stack, EntityPlayer player) { + MMDMaterial mat = Materials.getMaterialByName(MaterialNames.ADAMANTINE); + boolean rv = (stackIsArmorMaterial(stack, mat) + && ((stack.getItem() instanceof IMMDObject) && + (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && + (countArmorPieces(Materials.getMaterialByName(MaterialNames.ADAMANTINE),player) > 0); + + return rv; + } + + @Override + public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { + return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/properties/AdamantineToolProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/AdamantineToolProperty.java index e68182e3..f0f80e07 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/AdamantineToolProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/AdamantineToolProperty.java @@ -1,55 +1,55 @@ -package com.mcmoddev.basemetals.properties; - -import com.mcmoddev.basemetals.data.MaterialNames; -import com.mcmoddev.lib.material.IMMDObject; -import com.mcmoddev.lib.material.MMDMaterial; -import com.mcmoddev.lib.properties.MMDMaterialPropertyBase; - -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemStack; -import net.minecraft.util.DamageSource; - -public class AdamantineToolProperty extends MMDMaterialPropertyBase { - - @Override - public void apply(ItemStack stack) { - return; - } - - @Override - public void apply(ItemStack stack, EntityPlayer player) { - apply(stack, (EntityLivingBase)player); - } - - @Override - public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent)) { - if (ent.getMaxHealth() > 20f) { - final DamageSource extraDamage = DamageSource.GENERIC; - ent.attackEntityFrom(extraDamage, 4f); - } - } - } - - @Override - public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack - } - - @Override - public boolean hasEffect(ItemStack stack, EntityPlayer player) { - return hasEffect(stack, (EntityLivingBase)player); - } - - @Override - public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - if(stack.getItem() instanceof IMMDObject) { - MMDMaterial mat = ((IMMDObject)stack.getItem()).getMMDMaterial(); - return MaterialNames.ADAMANTINE.equals(mat.getName()) && (ent.getMaxHealth() > 20f); - } else { - return false; - } - } - -} +package com.mcmoddev.basemetals.properties; + +import com.mcmoddev.basemetals.data.MaterialNames; +import com.mcmoddev.lib.material.IMMDObject; +import com.mcmoddev.lib.material.MMDMaterial; +import com.mcmoddev.lib.properties.MMDMaterialPropertyBase; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.DamageSource; + +public class AdamantineToolProperty extends MMDMaterialPropertyBase { + + @Override + public void apply(ItemStack stack) { + return; + } + + @Override + public void apply(ItemStack stack, EntityPlayer player) { + apply(stack, (EntityLivingBase)player); + } + + @Override + public void apply(ItemStack stack, EntityLivingBase ent) { + if(hasEffect(stack, ent)) { + if (ent.getMaxHealth() > 20f) { + final DamageSource extraDamage = DamageSource.GENERIC; + ent.attackEntityFrom(extraDamage, 4f); + } + } + } + + @Override + public boolean hasEffect(ItemStack stack) { + return false; // no effect for just the stack + } + + @Override + public boolean hasEffect(ItemStack stack, EntityPlayer player) { + return hasEffect(stack, (EntityLivingBase)player); + } + + @Override + public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { + if(stack.getItem() instanceof IMMDObject) { + MMDMaterial mat = ((IMMDObject)stack.getItem()).getMMDMaterial(); + return MaterialNames.ADAMANTINE.equals(mat.getName()) && (ent.getMaxHealth() > 20f); + } else { + return false; + } + } + +} diff --git a/src/main/java/com/mcmoddev/basemetals/properties/AquariumProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/AquariumProperty.java index ead7531c..d36c702d 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/AquariumProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/AquariumProperty.java @@ -1,78 +1,61 @@ -package com.mcmoddev.basemetals.properties; - -import com.mcmoddev.basemetals.data.MaterialNames; -import com.mcmoddev.lib.init.Materials; -import com.mcmoddev.lib.material.IMMDObject; -import com.mcmoddev.lib.material.MMDMaterial; - -import net.minecraft.block.Block; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.Blocks; -import net.minecraft.init.MobEffects; -import net.minecraft.item.ItemStack; -import net.minecraft.potion.PotionEffect; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -public class AquariumProperty extends BMEPropertyBase { - @Override - public void apply(ItemStack stack) { - if(hasEffect(stack)) { - // only apply if there is an effect - // we should always double check here :) - } - } - - @Override - public void apply(ItemStack stack, EntityPlayer player) { - if(hasEffect(stack, player)) { - if ((hasFullSuit(player, MaterialNames.AQUARIUM)) && (player.posY > 0) - && (player.posY < 255)) { - World w = com.mcmoddev.basemetals.BaseMetals.proxy.getWorld(player.dimension); - if(w == null) return; - final Block b1 = w.getBlockState(new BlockPos(player.posX, player.posY, player.posZ)) - .getBlock(); - final Block b2 = w.getBlockState(new BlockPos(player.posX, player.posY + 1, player.posZ)) - .getBlock(); - if ((b1 == Blocks.WATER) && (b2 == Blocks.WATER)) { - final PotionEffect waterBreathing = new PotionEffect(MobEffects.WATER_BREATHING, - EFFECT_DURATION, 0, false, false); - player.addPotionEffect(waterBreathing); - final PotionEffect protection = new PotionEffect(MobEffects.RESISTANCE, - EFFECT_DURATION, 0, false, false); - player.addPotionEffect(protection); - player.removePotionEffect(MobEffects.MINING_FATIGUE); - } - } - } - } - - @Override - public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { - apply(stack, (EntityPlayer)ent); - } - } - - @Override - public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack - } - - @Override - public boolean hasEffect(ItemStack stack, EntityPlayer player) { - MMDMaterial mat = Materials.getMaterialByName(MaterialNames.AQUARIUM); - boolean rv = (stackIsArmorMaterial(stack, mat) - && ((stack.getItem() instanceof IMMDObject) && - (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && - (countArmorPieces(Materials.getMaterialByName(MaterialNames.AQUARIUM),player) > 0); - - return rv; - } - - @Override - public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; - } -} +package com.mcmoddev.basemetals.properties; + +import com.mcmoddev.basemetals.data.MaterialNames; +import com.mcmoddev.lib.init.Materials; +import com.mcmoddev.lib.material.IMMDObject; +import com.mcmoddev.lib.material.MMDMaterial; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.PotionEffect; + +public class AquariumProperty extends BMEPropertyBase { + @Override + public void apply(ItemStack stack) { + } + + @Override + public void apply(ItemStack stack, EntityPlayer player) { + if(hasEffect(stack, player)) { + if (hasFullSuit(player, MaterialNames.AQUARIUM) && player.isInWater()) { + final PotionEffect waterBreathing = new PotionEffect(MobEffects.WATER_BREATHING, + EFFECT_DURATION, 0, false, false); + player.addPotionEffect(waterBreathing); + final PotionEffect protection = new PotionEffect(MobEffects.RESISTANCE, + EFFECT_DURATION, 0, false, false); + player.addPotionEffect(protection); + player.removePotionEffect(MobEffects.MINING_FATIGUE); + } + } + } + + @Override + public void apply(ItemStack stack, EntityLivingBase ent) { + if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { + apply(stack, (EntityPlayer)ent); + } + } + + @Override + public boolean hasEffect(ItemStack stack) { + return false; // no effect for just the stack + } + + @Override + public boolean hasEffect(ItemStack stack, EntityPlayer player) { + MMDMaterial mat = Materials.getMaterialByName(MaterialNames.AQUARIUM); + boolean rv = (stackIsArmorMaterial(stack, mat) + && ((stack.getItem() instanceof IMMDObject) && + (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && + (countArmorPieces(Materials.getMaterialByName(MaterialNames.AQUARIUM),player) > 0); + + return rv; + } + + @Override + public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { + return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/properties/AquariumToolProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/AquariumToolProperty.java index bc3fab8a..449c6a0d 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/AquariumToolProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/AquariumToolProperty.java @@ -1,55 +1,55 @@ -package com.mcmoddev.basemetals.properties; - -import com.mcmoddev.basemetals.data.MaterialNames; -import com.mcmoddev.lib.material.IMMDObject; -import com.mcmoddev.lib.material.MMDMaterial; -import com.mcmoddev.lib.properties.MMDMaterialPropertyBase; - -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemStack; -import net.minecraft.util.DamageSource; - -public class AquariumToolProperty extends MMDMaterialPropertyBase { - - @Override - public void apply(ItemStack stack) { - return; - } - - @Override - public void apply(ItemStack stack, EntityPlayer player) { - apply(stack, (EntityLivingBase)player); - } - - @Override - public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent)) { - if (ent.canBreatheUnderwater()) { - final DamageSource extraDamage = DamageSource.GENERIC; - ent.attackEntityFrom(extraDamage, 4f); - } - } - } - - @Override - public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack - } - - @Override - public boolean hasEffect(ItemStack stack, EntityPlayer player) { - return hasEffect(stack, (EntityLivingBase)player); - } - - @Override - public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - if(stack.getItem() instanceof IMMDObject) { - MMDMaterial mat = ((IMMDObject)stack.getItem()).getMMDMaterial(); - return MaterialNames.AQUARIUM.equals(mat.getName()) && (ent.canBreatheUnderwater()); - } else { - return false; - } - } - -} +package com.mcmoddev.basemetals.properties; + +import com.mcmoddev.basemetals.data.MaterialNames; +import com.mcmoddev.lib.material.IMMDObject; +import com.mcmoddev.lib.material.MMDMaterial; +import com.mcmoddev.lib.properties.MMDMaterialPropertyBase; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.DamageSource; + +public class AquariumToolProperty extends MMDMaterialPropertyBase { + + @Override + public void apply(ItemStack stack) { + return; + } + + @Override + public void apply(ItemStack stack, EntityPlayer player) { + apply(stack, (EntityLivingBase)player); + } + + @Override + public void apply(ItemStack stack, EntityLivingBase ent) { + if(hasEffect(stack, ent)) { + if (ent.canBreatheUnderwater()) { + final DamageSource extraDamage = DamageSource.GENERIC; + ent.attackEntityFrom(extraDamage, 4f); + } + } + } + + @Override + public boolean hasEffect(ItemStack stack) { + return false; // no effect for just the stack + } + + @Override + public boolean hasEffect(ItemStack stack, EntityPlayer player) { + return hasEffect(stack, (EntityLivingBase)player); + } + + @Override + public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { + if(stack.getItem() instanceof IMMDObject) { + MMDMaterial mat = ((IMMDObject)stack.getItem()).getMMDMaterial(); + return MaterialNames.AQUARIUM.equals(mat.getName()) && (ent.canBreatheUnderwater()); + } else { + return false; + } + } + +} diff --git a/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertiesHelper.java b/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertiesHelper.java index f3afc41c..8f75be15 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertiesHelper.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertiesHelper.java @@ -1,79 +1,68 @@ -package com.mcmoddev.basemetals.properties; - -import java.util.ArrayList; -import java.util.List; - -import com.mcmoddev.basemetals.data.MaterialNames; - -import net.minecraft.client.resources.I18n; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - -public class BMEPropertiesHelper { - private static final String TOOLTIP = "tooltip."; - private static final String ARMOR = ".armor"; - private static final String TOOL = ".tool"; - - - /** - * - * @param materialName - * The materialName - * @param tooltipList - * The tooltip list - */ - @SideOnly(Side.CLIENT) - public static List addToolSpecialPropertiesToolTip(final String materialName) { - List rv = new ArrayList<>(); - switch (materialName) { - case MaterialNames.ADAMANTINE: - rv.add(I18n.format(TOOLTIP + MaterialNames.ADAMANTINE + TOOL, 4)); - break; - case MaterialNames.AQUARIUM: - rv.add(I18n.format(TOOLTIP + MaterialNames.AQUARIUM + TOOL, 4)); - break; - case MaterialNames.COLDIRON: - rv.add(I18n.format(TOOLTIP + MaterialNames.COLDIRON + TOOL, 3)); - break; - case MaterialNames.MITHRIL: - rv.add(I18n.format(TOOLTIP + MaterialNames.MITHRIL + TOOL)); - break; - case MaterialNames.STARSTEEL: - rv.add(I18n.format(TOOLTIP + MaterialNames.STARSTEEL + TOOL, 10)); - break; - default: - } - return rv; - } - - /** - * - * @param materialName - * The materialName - * @param tooltipList - * The tooltip list - */ - @SideOnly(Side.CLIENT) - public static List addArmorSpecialPropertiesToolTip(final String materialName) { - List rv = new ArrayList<>(); - switch (materialName) { - case MaterialNames.ADAMANTINE: - rv.add(I18n.format(TOOLTIP + MaterialNames.ADAMANTINE + ARMOR, 4)); - break; - case MaterialNames.AQUARIUM: - rv.add(I18n.format(TOOLTIP + MaterialNames.AQUARIUM + ARMOR, 4)); - break; - case MaterialNames.COLDIRON: - rv.add(I18n.format(TOOLTIP + MaterialNames.COLDIRON + ARMOR, 3)); - break; - case MaterialNames.MITHRIL: - rv.add(I18n.format(TOOLTIP + MaterialNames.MITHRIL + ARMOR)); - break; - case MaterialNames.STARSTEEL: - rv.add(I18n.format(TOOLTIP + MaterialNames.STARSTEEL + ARMOR, 10)); - break; - default: - } - return rv; - } -} +package com.mcmoddev.basemetals.properties; + +import java.util.ArrayList; +import java.util.List; + +import com.mcmoddev.basemetals.data.MaterialNames; + +import net.minecraft.client.resources.I18n; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +/** Builds localized tooltips for material-specific armor and tool effects. */ +public final class BMEPropertiesHelper { + private static final String TOOLTIP = "tooltip."; + private static final String ARMOR = ".armor"; + private static final String TOOL = ".tool"; + + + /** Returns the special tool-effect tooltip for a material, when it has one. */ + @SideOnly(Side.CLIENT) + public static List addToolSpecialPropertiesToolTip(final String materialName) { + List rv = new ArrayList<>(); + switch (materialName) { + case MaterialNames.ADAMANTINE: + rv.add(I18n.format(TOOLTIP + MaterialNames.ADAMANTINE + TOOL, 4)); + break; + case MaterialNames.AQUARIUM: + rv.add(I18n.format(TOOLTIP + MaterialNames.AQUARIUM + TOOL, 4)); + break; + case MaterialNames.COLDIRON: + rv.add(I18n.format(TOOLTIP + MaterialNames.COLDIRON + TOOL, 3)); + break; + case MaterialNames.MITHRIL: + rv.add(I18n.format(TOOLTIP + MaterialNames.MITHRIL + TOOL)); + break; + case MaterialNames.STARSTEEL: + rv.add(I18n.format(TOOLTIP + MaterialNames.STARSTEEL + TOOL, 10)); + break; + default: + } + return rv; + } + + /** Returns the special armor-effect tooltip for a material, when it has one. */ + @SideOnly(Side.CLIENT) + public static List addArmorSpecialPropertiesToolTip(final String materialName) { + List rv = new ArrayList<>(); + switch (materialName) { + case MaterialNames.ADAMANTINE: + rv.add(I18n.format(TOOLTIP + MaterialNames.ADAMANTINE + ARMOR, 4)); + break; + case MaterialNames.AQUARIUM: + rv.add(I18n.format(TOOLTIP + MaterialNames.AQUARIUM + ARMOR, 4)); + break; + case MaterialNames.COLDIRON: + rv.add(I18n.format(TOOLTIP + MaterialNames.COLDIRON + ARMOR, 3)); + break; + case MaterialNames.MITHRIL: + rv.add(I18n.format(TOOLTIP + MaterialNames.MITHRIL + ARMOR)); + break; + case MaterialNames.STARSTEEL: + rv.add(I18n.format(TOOLTIP + MaterialNames.STARSTEEL + ARMOR, 10)); + break; + default: + } + return rv; + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertyBase.java b/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertyBase.java index 3b64cc6d..be36531e 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertyBase.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertyBase.java @@ -1,50 +1,46 @@ -package com.mcmoddev.basemetals.properties; - -import java.util.Arrays; - -import com.mcmoddev.basemetals.init.Materials; -import com.mcmoddev.lib.data.Names; -import com.mcmoddev.lib.material.MMDMaterial; -import com.mcmoddev.lib.properties.MMDMaterialPropertyBase; - -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.inventory.EntityEquipmentSlot; -import net.minecraft.item.ItemStack; - -public abstract class BMEPropertyBase extends MMDMaterialPropertyBase { - protected static final int EFFECT_DURATION = 45; - - // Changing this to use getItem breaks the test. - private static boolean playerHasArmorItem(ItemStack piece, EntityPlayer player) { - return ((player.getItemStackFromSlot(EntityEquipmentSlot.HEAD) == piece) - || (player.getItemStackFromSlot(EntityEquipmentSlot.CHEST) == piece) - || (player.getItemStackFromSlot(EntityEquipmentSlot.LEGS) == piece) - || (player.getItemStackFromSlot(EntityEquipmentSlot.FEET) == piece)); - } - - protected static int countArmorPieces(final MMDMaterial mat, final EntityPlayer player) { - return (int) Arrays.stream(new Names[]{Names.HELMET, Names.CHESTPLATE, Names.LEGGINGS, Names.BOOTS}) - .map(n -> mat.getItemStack(n)) - .filter(m -> !playerHasArmorItem(m, player)) - .count(); - } - - protected static boolean hasFullSuit(final EntityPlayer player, final String materialName) { - final MMDMaterial material = Materials.getMaterialByName(materialName); - - return ((player.getItemStackFromSlot(EntityEquipmentSlot.HEAD).getItem() == material - .getItem(Names.HELMET)) - && (player.getItemStackFromSlot(EntityEquipmentSlot.CHEST).getItem() == material - .getItem(Names.CHESTPLATE)) - && (player.getItemStackFromSlot(EntityEquipmentSlot.LEGS).getItem() == material - .getItem(Names.LEGGINGS)) - && (player.getItemStackFromSlot(EntityEquipmentSlot.FEET).getItem() == material - .getItem(Names.BOOTS))); - } - - protected static boolean stackIsArmorMaterial(ItemStack stack, MMDMaterial material) { - return Arrays.stream(new Names[]{Names.HELMET, Names.CHESTPLATE, Names.LEGGINGS, Names.BOOTS}) - .map(n -> material.getItemStack(n)) - .anyMatch(it -> it.isItemEqual(stack)); - } -} +package com.mcmoddev.basemetals.properties; + +import java.util.Arrays; + +import com.mcmoddev.basemetals.init.Materials; +import com.mcmoddev.lib.data.Names; +import com.mcmoddev.lib.material.MMDMaterial; +import com.mcmoddev.lib.properties.MMDMaterialPropertyBase; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.ItemStack; + +public abstract class BMEPropertyBase extends MMDMaterialPropertyBase { + protected static final int EFFECT_DURATION = 45; + + protected static int countArmorPieces(final MMDMaterial mat, final EntityPlayer player) { + return (int) Arrays.stream(new EntityEquipmentSlot[] { + EntityEquipmentSlot.HEAD, + EntityEquipmentSlot.CHEST, + EntityEquipmentSlot.LEGS, + EntityEquipmentSlot.FEET + }) + .map(player::getItemStackFromSlot) + .filter(stack -> stackIsArmorMaterial(stack, mat)) + .count(); + } + + protected static boolean hasFullSuit(final EntityPlayer player, final String materialName) { + final MMDMaterial material = Materials.getMaterialByName(materialName); + + return ((player.getItemStackFromSlot(EntityEquipmentSlot.HEAD).getItem() == material + .getItem(Names.HELMET)) + && (player.getItemStackFromSlot(EntityEquipmentSlot.CHEST).getItem() == material + .getItem(Names.CHESTPLATE)) + && (player.getItemStackFromSlot(EntityEquipmentSlot.LEGS).getItem() == material + .getItem(Names.LEGGINGS)) + && (player.getItemStackFromSlot(EntityEquipmentSlot.FEET).getItem() == material + .getItem(Names.BOOTS))); + } + + protected static boolean stackIsArmorMaterial(ItemStack stack, MMDMaterial material) { + return Arrays.stream(new Names[]{Names.HELMET, Names.CHESTPLATE, Names.LEGGINGS, Names.BOOTS}) + .anyMatch(n -> stack.getItem() == material.getItem(n)); + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/properties/ColdIronProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/ColdIronProperty.java index fca940ac..0307f9a1 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/ColdIronProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/ColdIronProperty.java @@ -1,62 +1,57 @@ -package com.mcmoddev.basemetals.properties; - -import com.mcmoddev.basemetals.data.MaterialNames; -import com.mcmoddev.lib.init.Materials; -import com.mcmoddev.lib.material.IMMDObject; -import com.mcmoddev.lib.material.MMDMaterial; - -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.MobEffects; -import net.minecraft.item.ItemStack; -import net.minecraft.potion.PotionEffect; - -public class ColdIronProperty extends BMEPropertyBase { - @Override - public void apply(ItemStack stack) { - if(hasEffect(stack)) { - // only apply if there is an effect - // we should always double check here :) - } - } - - @Override - public void apply(ItemStack stack, EntityPlayer player) { - //if(hasEffect(stack, player)) { - if (hasFullSuit(player, MaterialNames.COLDIRON)) { - final PotionEffect fireProtection = new PotionEffect(MobEffects.FIRE_RESISTANCE, - EFFECT_DURATION, 0, false, false); - player.addPotionEffect(fireProtection); - } - //} - } - - @Override - public void apply(ItemStack stack, EntityLivingBase ent) { - if (ent instanceof EntityPlayer) { // Checks for full suit should be done in the second "apply" call - apply(stack, (EntityPlayer)ent); - } - } - - @Override - public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack - } - - @Override - public boolean hasEffect(ItemStack stack, EntityPlayer player) { - MMDMaterial mat = Materials.getMaterialByName(MaterialNames.COLDIRON); -/* - boolean rv = (stackIsArmorMaterial(stack, mat) - && ((stack.getItem() instanceof IMMDObject) && - (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && - (countArmorPieces(Materials.getMaterialByName(MaterialNames.COLDIRON),player) > 0); - */ - return true; - } - - @Override - public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; - } -} +package com.mcmoddev.basemetals.properties; + +import com.mcmoddev.basemetals.data.MaterialNames; +import com.mcmoddev.lib.init.Materials; +import com.mcmoddev.lib.material.IMMDObject; +import com.mcmoddev.lib.material.MMDMaterial; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.PotionEffect; + +public class ColdIronProperty extends BMEPropertyBase { + @Override + public void apply(ItemStack stack) { + } + + @Override + public void apply(ItemStack stack, EntityPlayer player) { + if(hasEffect(stack, player)) { + if (hasFullSuit(player, MaterialNames.COLDIRON)) { + final PotionEffect fireProtection = new PotionEffect(MobEffects.FIRE_RESISTANCE, + EFFECT_DURATION, 0, false, false); + player.addPotionEffect(fireProtection); + } + } + } + + @Override + public void apply(ItemStack stack, EntityLivingBase ent) { + if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { + apply(stack, (EntityPlayer)ent); + } + } + + @Override + public boolean hasEffect(ItemStack stack) { + return false; // no effect for just the stack + } + + @Override + public boolean hasEffect(ItemStack stack, EntityPlayer player) { + MMDMaterial mat = Materials.getMaterialByName(MaterialNames.COLDIRON); + boolean rv = (stackIsArmorMaterial(stack, mat) + && ((stack.getItem() instanceof IMMDObject) && + (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && + (countArmorPieces(Materials.getMaterialByName(MaterialNames.COLDIRON),player) > 0); + + return rv; + } + + @Override + public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { + return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/properties/ColdIronToolProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/ColdIronToolProperty.java index 54bd0c69..9222c376 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/ColdIronToolProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/ColdIronToolProperty.java @@ -1,53 +1,53 @@ -package com.mcmoddev.basemetals.properties; - -import com.mcmoddev.basemetals.data.MaterialNames; -import com.mcmoddev.lib.material.IMMDObject; -import com.mcmoddev.lib.material.MMDMaterial; -import com.mcmoddev.lib.properties.MMDMaterialPropertyBase; - -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemStack; -import net.minecraft.util.DamageSource; - -public class ColdIronToolProperty extends MMDMaterialPropertyBase { - - @Override - public void apply(ItemStack stack) { - return; - } - - @Override - public void apply(ItemStack stack, EntityPlayer player) { - apply(stack, (EntityLivingBase)player); - } - - @Override - public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent)) { - final DamageSource extraDamage = DamageSource.GENERIC; - ent.attackEntityFrom(extraDamage, 3f); - } - } - - @Override - public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack - } - - @Override - public boolean hasEffect(ItemStack stack, EntityPlayer player) { - return hasEffect(stack, (EntityLivingBase)player); - } - - @Override - public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - if(stack.getItem() instanceof IMMDObject) { - MMDMaterial mat = ((IMMDObject)stack.getItem()).getMMDMaterial(); - return MaterialNames.COLDIRON.equals(mat.getName()) && ent.isImmuneToFire(); - } else { - return false; - } - } - -} +package com.mcmoddev.basemetals.properties; + +import com.mcmoddev.basemetals.data.MaterialNames; +import com.mcmoddev.lib.material.IMMDObject; +import com.mcmoddev.lib.material.MMDMaterial; +import com.mcmoddev.lib.properties.MMDMaterialPropertyBase; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.DamageSource; + +public class ColdIronToolProperty extends MMDMaterialPropertyBase { + + @Override + public void apply(ItemStack stack) { + return; + } + + @Override + public void apply(ItemStack stack, EntityPlayer player) { + apply(stack, (EntityLivingBase)player); + } + + @Override + public void apply(ItemStack stack, EntityLivingBase ent) { + if(hasEffect(stack, ent)) { + final DamageSource extraDamage = DamageSource.GENERIC; + ent.attackEntityFrom(extraDamage, 3f); + } + } + + @Override + public boolean hasEffect(ItemStack stack) { + return false; // no effect for just the stack + } + + @Override + public boolean hasEffect(ItemStack stack, EntityPlayer player) { + return hasEffect(stack, (EntityLivingBase)player); + } + + @Override + public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { + if(stack.getItem() instanceof IMMDObject) { + MMDMaterial mat = ((IMMDObject)stack.getItem()).getMMDMaterial(); + return MaterialNames.COLDIRON.equals(mat.getName()) && ent.isImmuneToFire(); + } else { + return false; + } + } + +} diff --git a/src/main/java/com/mcmoddev/basemetals/properties/LeadProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/LeadProperty.java index 652e7506..b7ae40a8 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/LeadProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/LeadProperty.java @@ -1,65 +1,61 @@ -package com.mcmoddev.basemetals.properties; - -import com.mcmoddev.basemetals.data.MaterialNames; -import com.mcmoddev.lib.init.Materials; -import com.mcmoddev.lib.material.IMMDObject; -import com.mcmoddev.lib.material.MMDMaterial; - -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.MobEffects; -import net.minecraft.item.ItemStack; -import net.minecraft.potion.PotionEffect; - -public class LeadProperty extends BMEPropertyBase { - @Override - public void apply(ItemStack stack) { - if(hasEffect(stack)) { - // only apply if there is an effect - // we should always double check here :) - } - } - - @Override - public void apply(ItemStack stack, EntityPlayer player) { - if(hasEffect(stack, player)) { - final int level = countArmorPieces(Materials.getMaterialByName(MaterialNames.LEAD), player) / 2; - if (level == 0) { - return; - } - if (level > 0) { - final PotionEffect speedLoss = new PotionEffect(MobEffects.SLOWNESS, EFFECT_DURATION, - level - 1, false, false); - player.addPotionEffect(speedLoss); - } - } - } - - @Override - public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { - apply(stack, (EntityPlayer)ent); - } - } - - @Override - public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack - } - - @Override - public boolean hasEffect(ItemStack stack, EntityPlayer player) { - MMDMaterial mat = Materials.getMaterialByName(MaterialNames.LEAD); - boolean rv = (stackIsArmorMaterial(stack, mat) - && ((stack.getItem() instanceof IMMDObject) && - (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && - (countArmorPieces(Materials.getMaterialByName(MaterialNames.LEAD),player) > 0); - - return rv; - } - - @Override - public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; - } -} +package com.mcmoddev.basemetals.properties; + +import com.mcmoddev.basemetals.data.MaterialNames; +import com.mcmoddev.lib.init.Materials; +import com.mcmoddev.lib.material.IMMDObject; +import com.mcmoddev.lib.material.MMDMaterial; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.PotionEffect; + +public class LeadProperty extends BMEPropertyBase { + @Override + public void apply(ItemStack stack) { + } + + @Override + public void apply(ItemStack stack, EntityPlayer player) { + if(hasEffect(stack, player)) { + final int level = countArmorPieces(Materials.getMaterialByName(MaterialNames.LEAD), player) / 2; + if (level == 0) { + return; + } + if (level > 0) { + final PotionEffect speedLoss = new PotionEffect(MobEffects.SLOWNESS, EFFECT_DURATION, + level - 1, false, false); + player.addPotionEffect(speedLoss); + } + } + } + + @Override + public void apply(ItemStack stack, EntityLivingBase ent) { + if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { + apply(stack, (EntityPlayer)ent); + } + } + + @Override + public boolean hasEffect(ItemStack stack) { + return false; // no effect for just the stack + } + + @Override + public boolean hasEffect(ItemStack stack, EntityPlayer player) { + MMDMaterial mat = Materials.getMaterialByName(MaterialNames.LEAD); + boolean rv = (stackIsArmorMaterial(stack, mat) + && ((stack.getItem() instanceof IMMDObject) && + (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && + (countArmorPieces(Materials.getMaterialByName(MaterialNames.LEAD),player) > 0); + + return rv; + } + + @Override + public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { + return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/properties/MithrilProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/MithrilProperty.java index 67176e27..484ffed5 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/MithrilProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/MithrilProperty.java @@ -1,76 +1,72 @@ -package com.mcmoddev.basemetals.properties; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import com.mcmoddev.basemetals.data.MaterialNames; -import com.mcmoddev.lib.init.Materials; -import com.mcmoddev.lib.material.IMMDObject; -import com.mcmoddev.lib.material.MMDMaterial; - -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemStack; -import net.minecraft.potion.Potion; -import net.minecraft.potion.PotionEffect; - -public class MithrilProperty extends BMEPropertyBase { - @Override - public void apply(ItemStack stack) { - if(hasEffect(stack)) { - // only apply if there is an effect - // we should always double check here :) - } - } - - @Override - public void apply(ItemStack stack, EntityPlayer player) { - if(hasEffect(stack, player)) { - if (hasFullSuit(player, MaterialNames.MITHRIL)) { - final List removeList = new LinkedList<>(); // needed to avoid concurrent - // modification error - final Iterator effectIterator = player.getActivePotionEffects() - .iterator(); - while (effectIterator.hasNext()) { - final PotionEffect pe = effectIterator.next(); - final Potion p = pe.getPotion(); - if (p.isBadEffect()) { - removeList.add(p); - } - } - for (final Potion p : removeList) { - player.removePotionEffect(p); - } - } - } - } - - @Override - public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { - apply(stack, (EntityPlayer)ent); - } - } - - @Override - public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack - } - - @Override - public boolean hasEffect(ItemStack stack, EntityPlayer player) { - MMDMaterial mat = Materials.getMaterialByName(MaterialNames.MITHRIL); - boolean rv = (stackIsArmorMaterial(stack, mat) - && ((stack.getItem() instanceof IMMDObject) && - (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && - (countArmorPieces(Materials.getMaterialByName(MaterialNames.MITHRIL),player) > 0); - - return rv; - } - - @Override - public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; - } -} +package com.mcmoddev.basemetals.properties; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import com.mcmoddev.basemetals.data.MaterialNames; +import com.mcmoddev.lib.init.Materials; +import com.mcmoddev.lib.material.IMMDObject; +import com.mcmoddev.lib.material.MMDMaterial; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; + +public class MithrilProperty extends BMEPropertyBase { + @Override + public void apply(ItemStack stack) { + } + + @Override + public void apply(ItemStack stack, EntityPlayer player) { + if(hasEffect(stack, player)) { + if (hasFullSuit(player, MaterialNames.MITHRIL)) { + // Collect first because removing effects while iterating would modify the source collection. + final List removeList = new LinkedList<>(); + final Iterator effectIterator = player.getActivePotionEffects() + .iterator(); + while (effectIterator.hasNext()) { + final PotionEffect pe = effectIterator.next(); + final Potion p = pe.getPotion(); + if (p.isBadEffect()) { + removeList.add(p); + } + } + for (final Potion p : removeList) { + player.removePotionEffect(p); + } + } + } + } + + @Override + public void apply(ItemStack stack, EntityLivingBase ent) { + if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { + apply(stack, (EntityPlayer)ent); + } + } + + @Override + public boolean hasEffect(ItemStack stack) { + return false; // no effect for just the stack + } + + @Override + public boolean hasEffect(ItemStack stack, EntityPlayer player) { + MMDMaterial mat = Materials.getMaterialByName(MaterialNames.MITHRIL); + boolean rv = (stackIsArmorMaterial(stack, mat) + && ((stack.getItem() instanceof IMMDObject) && + (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && + (countArmorPieces(Materials.getMaterialByName(MaterialNames.MITHRIL),player) > 0); + + return rv; + } + + @Override + public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { + return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/properties/MithrilToolProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/MithrilToolProperty.java index e023dbf3..ed49f6ce 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/MithrilToolProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/MithrilToolProperty.java @@ -1,59 +1,59 @@ -package com.mcmoddev.basemetals.properties; - -import com.mcmoddev.basemetals.data.MaterialNames; -import com.mcmoddev.lib.material.IMMDObject; -import com.mcmoddev.lib.material.MMDMaterial; -import com.mcmoddev.lib.properties.MMDMaterialPropertyBase; - -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.EnumCreatureAttribute; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.MobEffects; -import net.minecraft.item.ItemStack; -import net.minecraft.potion.PotionEffect; - -public class MithrilToolProperty extends MMDMaterialPropertyBase { - - @Override - public void apply(ItemStack stack) { - return; - } - - @Override - public void apply(ItemStack stack, EntityPlayer player) { - apply(stack, (EntityLivingBase)player); - } - - @Override - public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent)) { - if (ent.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD) { - final PotionEffect wither = new PotionEffect(MobEffects.WITHER, 60, 3); - final PotionEffect blind = new PotionEffect(MobEffects.BLINDNESS, 60, 1); - ent.addPotionEffect(wither); - ent.addPotionEffect(blind); - } - } - } - - @Override - public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack - } - - @Override - public boolean hasEffect(ItemStack stack, EntityPlayer player) { - return hasEffect(stack, (EntityLivingBase)player); - } - - @Override - public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - if(stack.getItem() instanceof IMMDObject) { - MMDMaterial mat = ((IMMDObject)stack.getItem()).getMMDMaterial(); - return MaterialNames.MITHRIL.equals(mat.getName()) && (ent.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD); - } else { - return false; - } - } - -} +package com.mcmoddev.basemetals.properties; + +import com.mcmoddev.basemetals.data.MaterialNames; +import com.mcmoddev.lib.material.IMMDObject; +import com.mcmoddev.lib.material.MMDMaterial; +import com.mcmoddev.lib.properties.MMDMaterialPropertyBase; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.EnumCreatureAttribute; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.PotionEffect; + +public class MithrilToolProperty extends MMDMaterialPropertyBase { + + @Override + public void apply(ItemStack stack) { + return; + } + + @Override + public void apply(ItemStack stack, EntityPlayer player) { + apply(stack, (EntityLivingBase)player); + } + + @Override + public void apply(ItemStack stack, EntityLivingBase ent) { + if(hasEffect(stack, ent)) { + if (ent.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD) { + final PotionEffect wither = new PotionEffect(MobEffects.WITHER, 60, 3); + final PotionEffect blind = new PotionEffect(MobEffects.BLINDNESS, 60, 1); + ent.addPotionEffect(wither); + ent.addPotionEffect(blind); + } + } + } + + @Override + public boolean hasEffect(ItemStack stack) { + return false; // no effect for just the stack + } + + @Override + public boolean hasEffect(ItemStack stack, EntityPlayer player) { + return hasEffect(stack, (EntityLivingBase)player); + } + + @Override + public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { + if(stack.getItem() instanceof IMMDObject) { + MMDMaterial mat = ((IMMDObject)stack.getItem()).getMMDMaterial(); + return MaterialNames.MITHRIL.equals(mat.getName()) && (ent.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD); + } else { + return false; + } + } + +} diff --git a/src/main/java/com/mcmoddev/basemetals/properties/StarSteelProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/StarSteelProperty.java index 2220f80e..2283a77b 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/StarSteelProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/StarSteelProperty.java @@ -1,68 +1,64 @@ -package com.mcmoddev.basemetals.properties; - -import com.mcmoddev.basemetals.data.MaterialNames; -import com.mcmoddev.lib.init.Materials; -import com.mcmoddev.lib.material.IMMDObject; -import com.mcmoddev.lib.material.MMDMaterial; - -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.MobEffects; -import net.minecraft.item.ItemStack; -import net.minecraft.potion.PotionEffect; - -public class StarSteelProperty extends BMEPropertyBase { - @Override - public void apply(ItemStack stack) { - if(hasEffect(stack)) { - // only apply if there is an effect - // we should always double check here :) - } - } - - @Override - public void apply(ItemStack stack, EntityPlayer player) { - if(hasEffect(stack, player)) { - final int num = countArmorPieces(Materials.getMaterialByName(MaterialNames.STARSTEEL), player); - if (num == 0) { - return; - } - final PotionEffect jumpBoost = new PotionEffect(MobEffects.JUMP_BOOST, EFFECT_DURATION, - num - 1, false, false); - player.addPotionEffect(jumpBoost); - if (num > 1) { - final PotionEffect speedBoost = new PotionEffect(MobEffects.SPEED, EFFECT_DURATION, - num - 2, false, false); - player.addPotionEffect(speedBoost); - } - } - } - - @Override - public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { - apply(stack, (EntityPlayer)ent); - } - } - - @Override - public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack - } - - @Override - public boolean hasEffect(ItemStack stack, EntityPlayer player) { - MMDMaterial mat = Materials.getMaterialByName(MaterialNames.STARSTEEL); - boolean rv = (stackIsArmorMaterial(stack, mat) - && ((stack.getItem() instanceof IMMDObject) && - (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && - (countArmorPieces(Materials.getMaterialByName(MaterialNames.STARSTEEL),player) > 0); - - return rv; - } - - @Override - public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; - } -} +package com.mcmoddev.basemetals.properties; + +import com.mcmoddev.basemetals.data.MaterialNames; +import com.mcmoddev.lib.init.Materials; +import com.mcmoddev.lib.material.IMMDObject; +import com.mcmoddev.lib.material.MMDMaterial; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.MobEffects; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.PotionEffect; + +public class StarSteelProperty extends BMEPropertyBase { + @Override + public void apply(ItemStack stack) { + } + + @Override + public void apply(ItemStack stack, EntityPlayer player) { + if(hasEffect(stack, player)) { + final int num = countArmorPieces(Materials.getMaterialByName(MaterialNames.STARSTEEL), player); + if (num == 0) { + return; + } + final PotionEffect jumpBoost = new PotionEffect(MobEffects.JUMP_BOOST, EFFECT_DURATION, + num - 1, false, false); + player.addPotionEffect(jumpBoost); + if (num > 1) { + final PotionEffect speedBoost = new PotionEffect(MobEffects.SPEED, EFFECT_DURATION, + num - 2, false, false); + player.addPotionEffect(speedBoost); + } + } + } + + @Override + public void apply(ItemStack stack, EntityLivingBase ent) { + if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { + apply(stack, (EntityPlayer)ent); + } + } + + @Override + public boolean hasEffect(ItemStack stack) { + return false; // no effect for just the stack + } + + @Override + public boolean hasEffect(ItemStack stack, EntityPlayer player) { + MMDMaterial mat = Materials.getMaterialByName(MaterialNames.STARSTEEL); + boolean rv = (stackIsArmorMaterial(stack, mat) + && ((stack.getItem() instanceof IMMDObject) && + (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && + (countArmorPieces(Materials.getMaterialByName(MaterialNames.STARSTEEL),player) > 0); + + return rv; + } + + @Override + public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { + return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/proxy/ClientProxy.java b/src/main/java/com/mcmoddev/basemetals/proxy/ClientProxy.java index f94590f0..3f707e3c 100644 --- a/src/main/java/com/mcmoddev/basemetals/proxy/ClientProxy.java +++ b/src/main/java/com/mcmoddev/basemetals/proxy/ClientProxy.java @@ -3,9 +3,11 @@ import javax.annotation.Nullable; import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.client.config.BaseMetalsConfigScreen; +import com.mcmoddev.basemetals.network.ClientContentModeConnectionHandler; +import com.mcmoddev.basemetals.client.renderer.RenderBaseMetalsBolt; import com.mcmoddev.lib.client.registrations.RegistrationHelper; import com.mcmoddev.lib.client.renderer.RenderCustomArrow; -import com.mcmoddev.lib.client.renderer.RenderCustomBolt; import com.mcmoddev.lib.data.Names; import com.mcmoddev.lib.entity.EntityCustomArrow; import com.mcmoddev.lib.entity.EntityCustomBolt; @@ -22,6 +24,7 @@ import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.client.registry.RenderingRegistry; import net.minecraftforge.fml.common.Loader; @@ -31,32 +34,25 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import zone.moddev.mc.orespawn.api.client.WorldSettingsExtensionRegistry; -/** - * Base Metals Client Proxy. - * - * @author Jasmine Iwanek - * - */ +/** Client-only rendering, configuration-screen, and world access setup. */ @EventBusSubscriber public final class ClientProxy extends CommonProxy { @Override public void preInit(final FMLPreInitializationEvent event) { super.preInit(event); + FMLCommonHandler.instance().bus().register(new ClientContentModeConnectionHandler()); RenderingRegistry.registerEntityRenderingHandler(EntityCustomArrow.class, RenderCustomArrow::new); RenderingRegistry.registerEntityRenderingHandler(EntityCustomBolt.class, - RenderCustomBolt::new); + RenderBaseMetalsBolt::new); MinecraftForge.EVENT_BUS.register(this); } - /** - * Registers Block and Item models for this mod. - * - * @param event The Event. - */ + /** Registers item and block models, including the three anvil damage states. */ @SubscribeEvent public static void registerModels(final ModelRegistryEvent event) { for (final String name : Items.getItemRegistry().keySet()) { @@ -80,11 +76,7 @@ public static void registerModels(final ModelRegistryEvent event) { } } - /** - * Registers Fluid models for this mod. - * - * @param event The Event. - */ + /** Registers models for every Base Metals fluid block. */ @SubscribeEvent public void fluidRendering(final RegistryEvent.Register event) { for (final String name : Fluids.getFluidBlockRegistry().keySet()) { @@ -95,6 +87,8 @@ public void fluidRendering(final RegistryEvent.Register event) { @Override public void init(final FMLInitializationEvent event) { super.init(event); + WorldSettingsExtensionRegistry.registerConfigScreen(BaseMetals.MODID, + BaseMetalsConfigScreen::new); if (Loader.isModLoaded("waila")) { com.mcmoddev.lib.waila.Waila.init(); } diff --git a/src/main/java/com/mcmoddev/basemetals/proxy/CommonProxy.java b/src/main/java/com/mcmoddev/basemetals/proxy/CommonProxy.java index 8ca1ff53..21d7cc54 100644 --- a/src/main/java/com/mcmoddev/basemetals/proxy/CommonProxy.java +++ b/src/main/java/com/mcmoddev/basemetals/proxy/CommonProxy.java @@ -7,6 +7,8 @@ import com.mcmoddev.basemetals.data.MaterialNames; import com.mcmoddev.basemetals.init.ItemGroups; import com.mcmoddev.basemetals.init.Materials; +import com.mcmoddev.basemetals.loot.ContentModeLootCondition; +import com.mcmoddev.basemetals.network.ContentModeNetwork; import com.mcmoddev.basemetals.util.EventHandler; import com.mcmoddev.lib.data.Names; @@ -18,28 +20,17 @@ import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; -/** - * Base Metals Common Proxy. - * - * @author Jasmine Iwanek - * - */ +/** Common setup shared by the client and dedicated server. */ public class CommonProxy { - /** - * Pre Initialization for this mod. - * - * @param event The Event. - */ + /** Registers networking, loot conditions, and common event handlers. */ public void preInit(final FMLPreInitializationEvent event) { + ContentModeNetwork.init(); + ContentModeLootCondition.register(); MinecraftForge.EVENT_BUS.register(com.mcmoddev.basemetals.BaseMetals.class); } - /** - * Fired when Blocks get Remapped. - * - * @param event The Event. - */ + /** Maps the old liquid-mercury block ID to the current fluid block. */ public void onRemapBlock(final RegistryEvent.MissingMappings event) { for (final RegistryEvent.MissingMappings.Mapping mapping : event.getAllMappings()) { if (mapping.key.getNamespace().equals(BaseMetals.MODID) @@ -51,11 +42,7 @@ public void onRemapBlock(final RegistryEvent.MissingMappings event) { } } - /** - * Fired when Items Get Remapped. - * - * @param event The Event. - */ + /** Maps the old carbon-powder item ID to coal powder. */ public void onRemapItem(final RegistryEvent.MissingMappings event) { for (final RegistryEvent.MissingMappings.Mapping mapping : event.getAllMappings()) { if (mapping.key.getNamespace().equals(BaseMetals.MODID) @@ -67,21 +54,12 @@ public void onRemapItem(final RegistryEvent.MissingMappings event) { } } - /** - * Initialization for this mod. - * - * @param event The Event. - */ + /** Registers gameplay handlers and chooses the creative-tab icons. */ public void init(final FMLInitializationEvent event) { MinecraftForge.EVENT_BUS.register(new EventHandler()); ItemGroups.setupIcons(MaterialNames.STARSTEEL); } - /** - * Post Initialization for this mod. - * - * @param event The Event. - */ public void postInit(final FMLPostInitializationEvent event) { } diff --git a/src/main/java/com/mcmoddev/basemetals/proxy/ServerProxy.java b/src/main/java/com/mcmoddev/basemetals/proxy/ServerProxy.java index b62c4c5a..1e0a2d5b 100644 --- a/src/main/java/com/mcmoddev/basemetals/proxy/ServerProxy.java +++ b/src/main/java/com/mcmoddev/basemetals/proxy/ServerProxy.java @@ -5,14 +5,8 @@ import net.minecraft.world.World; import net.minecraftforge.fml.common.FMLCommonHandler; -/** - * Base Metals Server Proxy. - * - * @author Jasmine Iwanek - * - */ +/** Provides dedicated-server access to dimension worlds. */ public final class ServerProxy extends CommonProxy { - // Nothing to see here people @Override public World getWorld(@Nullable final int dimension) { return FMLCommonHandler.instance().getMinecraftServerInstance().getWorld(dimension); diff --git a/src/main/java/com/mcmoddev/basemetals/recipe/ContentAcquisitionFilters.java b/src/main/java/com/mcmoddev/basemetals/recipe/ContentAcquisitionFilters.java new file mode 100644 index 00000000..319206e1 --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/recipe/ContentAcquisitionFilters.java @@ -0,0 +1,74 @@ +package com.mcmoddev.basemetals.recipe; + +import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.content.ContentMode; +import com.mcmoddev.basemetals.content.ContentPolicy; +import com.mcmoddev.lib.registry.CrusherRecipeRegistry; +import com.mcmoddev.lib.registry.recipe.ICrusherRecipe; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.FurnaceRecipes; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.event.RegistryEvent; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** Applies the latched mode to Base Metals-owned acquisition registries. */ +public final class ContentAcquisitionFilters { + private ContentAcquisitionFilters() { + } + + public static void apply(final RegistryEvent.Register event) { + final ContentPolicy policy = ContentPolicy.active(); + if (policy.mode() == ContentMode.HIGH_FANTASY) { + return; + } + wrapCraftingRecipes(event, policy); + filterFurnaceRecipes(policy); + filterCrusherRecipes(policy); + } + + private static void wrapCraftingRecipes(final RegistryEvent.Register event, + final ContentPolicy policy) { + final List recipes = new ArrayList<>(); + for (final IRecipe recipe : event.getRegistry()) { + if (recipe.getRegistryName() != null + && BaseMetals.MODID.equals(recipe.getRegistryName().getNamespace())) { + recipes.add(recipe); + } + } + for (final IRecipe recipe : recipes) { + final PolicyRecipe wrapped = new PolicyRecipe(recipe, policy); + if (!wrapped.isAllowed()) { + event.getRegistry().register(wrapped); + } + } + } + + private static void filterFurnaceRecipes(final ContentPolicy policy) { + final Map recipes = FurnaceRecipes.instance().getSmeltingList(); + final List> snapshot = + new ArrayList<>(recipes.entrySet()); + for (final Map.Entry recipe : snapshot) { + if (!policy.allows(recipe.getValue())) { + recipes.remove(recipe.getKey()); + } + } + } + + private static void filterCrusherRecipes(final ContentPolicy policy) { + final List recipes = CrusherRecipeRegistry.getAll(); + for (final ICrusherRecipe recipe : recipes) { + if (!policy.allows(recipe.getOutput())) { + final ResourceLocation id = recipe.getRegistryName(); + if (id != null) { + CrusherRecipeRegistry.removeByName(id); + CrusherRecipeRegistry.getInstance().register( + new PolicyCrusherRecipe(recipe)); + } + } + } + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/recipe/PolicyCrusherRecipe.java b/src/main/java/com/mcmoddev/basemetals/recipe/PolicyCrusherRecipe.java new file mode 100644 index 00000000..dcf76b3f --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/recipe/PolicyCrusherRecipe.java @@ -0,0 +1,41 @@ +package com.mcmoddev.basemetals.recipe; + +import com.mcmoddev.lib.registry.recipe.ICrusherRecipe; +import net.minecraft.item.ItemStack; +import net.minecraftforge.registries.IForgeRegistryEntry; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Retains a crusher recipe's persistent registry identity while making a + * policy-restricted acquisition route non-matching and invisible. + */ +final class PolicyCrusherRecipe extends IForgeRegistryEntry.Impl + implements ICrusherRecipe { + + PolicyCrusherRecipe(final ICrusherRecipe delegate) { + setRegistryName(delegate.getRegistryName()); + } + + @Override + public List getInputs() { + return Collections.emptyList(); + } + + @Override + public ItemStack getOutput() { + return ItemStack.EMPTY; + } + + @Override + public boolean isValidInput(final ItemStack input) { + return false; + } + + @Override + public Collection getValidInputs() { + return Collections.emptyList(); + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/recipe/PolicyRecipe.java b/src/main/java/com/mcmoddev/basemetals/recipe/PolicyRecipe.java new file mode 100644 index 00000000..58777d9b --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/recipe/PolicyRecipe.java @@ -0,0 +1,67 @@ +package com.mcmoddev.basemetals.recipe; + +import com.mcmoddev.basemetals.content.ContentPolicy; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.NonNullList; +import net.minecraft.world.World; +import net.minecraftforge.registries.IForgeRegistryEntry; + +/** Keeps recipe registry identity stable while disabling acquisition in restricted modes. */ +final class PolicyRecipe extends IForgeRegistryEntry.Impl implements IRecipe { + private final IRecipe delegate; + private final boolean allowed; + + PolicyRecipe(final IRecipe delegate, final ContentPolicy policy) { + this.delegate = delegate; + final ItemStack output = delegate.getRecipeOutput(); + this.allowed = !output.isEmpty() ? policy.allows(output) + : policy.allowsRecipeId(delegate.getRegistryName()); + setRegistryName(delegate.getRegistryName()); + } + + boolean isAllowed() { + return allowed; + } + + @Override + public boolean matches(final InventoryCrafting inventory, final World world) { + return allowed && delegate.matches(inventory, world); + } + + @Override + public ItemStack getCraftingResult(final InventoryCrafting inventory) { + return allowed ? delegate.getCraftingResult(inventory) : ItemStack.EMPTY; + } + + @Override + public boolean canFit(final int width, final int height) { + return allowed && delegate.canFit(width, height); + } + + @Override + public ItemStack getRecipeOutput() { + return allowed ? delegate.getRecipeOutput() : ItemStack.EMPTY; + } + + @Override + public NonNullList getRemainingItems(final InventoryCrafting inventory) { + return delegate.getRemainingItems(inventory); + } + + @Override + public NonNullList getIngredients() { + return delegate.getIngredients(); + } + + @Override + public boolean isDynamic() { + return !allowed || delegate.isDynamic(); + } + + @Override + public String getGroup() { + return delegate.getGroup(); + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/util/BMeConfig.java b/src/main/java/com/mcmoddev/basemetals/util/BMeConfig.java index 65b1f404..43ad3632 100644 --- a/src/main/java/com/mcmoddev/basemetals/util/BMeConfig.java +++ b/src/main/java/com/mcmoddev/basemetals/util/BMeConfig.java @@ -1,28 +1,63 @@ package com.mcmoddev.basemetals.util; import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.content.ContentMode; import com.mcmoddev.basemetals.data.MaterialNames; import com.mcmoddev.lib.util.Config; import com.mcmoddev.lib.util.MaterialConfigOptions; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.config.ConfigCategory; import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.common.config.Property; import net.minecraftforge.fml.client.event.ConfigChangedEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.apache.commons.lang3.text.WordUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; -/** - * @author Jasmine Iwanek - * - */ +/** Owns the legacy configuration file and the startup-latched content policy. */ public final class BMeConfig extends Config { + private static final Logger LOGGER = LogManager.getFormatterLogger("basemetals"); private static Configuration configuration; + private static volatile ContentMode activeContentMode = ContentMode.HIGH_FANTASY; + private static boolean contentModeLatched; private static final String CONFIG_FILE = "config/BaseMetals.cfg"; - private static final String GENERAL_CAT = "General"; + public static final String CONTENT_MODE_PROPERTY = "contentMode"; + public static final String GENERAL_CAT = "General"; + public static final String MATERIALS_CAT = "Metals"; + public static final String VANILLA_CAT = "Vanilla"; + public static final String FLUIDS_CAT = "Fluids"; + public static final String FORCED_TRAITS_CAT = "Forced Traits"; + public static final List GUI_CATEGORIES = Collections.unmodifiableList(Arrays.asList( + GENERAL_CAT, MATERIALS_CAT, VANILLA_CAT, FLUIDS_CAT, FORCED_TRAITS_CAT)); + + private static final Map GENERATED_ORE_RULES; + static { + final Map rules = new LinkedHashMap<>(); + rules.put(MaterialNames.COLDIRON, "basemetals:legacy/coldiron_ore"); + rules.put(MaterialNames.ADAMANTINE, "basemetals:legacy/adamantine_ore"); + rules.put(MaterialNames.STARSTEEL, "basemetals:legacy/starsteel_ore"); + rules.put(MaterialNames.COPPER, "basemetals:legacy/copper_ore"); + rules.put(MaterialNames.SILVER, "basemetals:legacy/silver_ore"); + rules.put(MaterialNames.TIN, "basemetals:legacy/tin_ore"); + rules.put(MaterialNames.LEAD, "basemetals:legacy/lead_ore"); + rules.put(MaterialNames.ZINC, "basemetals:legacy/zinc_ore"); + rules.put(MaterialNames.MERCURY, "basemetals:legacy/mercury_ore"); + rules.put(MaterialNames.NICKEL, "basemetals:legacy/nickel_ore"); + rules.put(MaterialNames.PLATINUM, "basemetals:legacy/platinum_ore"); + GENERATED_ORE_RULES = Collections.unmodifiableMap(rules); + } private static final MaterialConfigOptions[] MATERIAL_CONFIG_OPTIONS = new MaterialConfigOptions[]{ - // Base Metals + // Base Metals material switches. new MaterialConfigOptions(MaterialNames.ADAMANTINE, false, true, true, true, true), new MaterialConfigOptions(MaterialNames.ANTIMONY, false, true, true, true, true), new MaterialConfigOptions(MaterialNames.AQUARIUM, false, true, true, true, true), @@ -45,13 +80,26 @@ public final class BMeConfig extends Config { new MaterialConfigOptions(MaterialNames.STEEL, false, true, true, true, true), new MaterialConfigOptions(MaterialNames.TIN, false, true, true, true, true), new MaterialConfigOptions(MaterialNames.ZINC, false, true, true, true, true), + + // Vanilla Bits. These entries were present in the 2.5.0 release and are + // required before MMDLib fires the material item/block registration events. + new MaterialConfigOptions(MaterialNames.CHARCOAL, true, true, true, true), + new MaterialConfigOptions(MaterialNames.COAL, true, true, true, true), + new MaterialConfigOptions(MaterialNames.DIAMOND, true, true, true, true), + new MaterialConfigOptions(MaterialNames.EMERALD, true, true, true, true), + new MaterialConfigOptions(MaterialNames.GOLD, true, true, true, true), + new MaterialConfigOptions(MaterialNames.IRON, true, true, true, true), + new MaterialConfigOptions(MaterialNames.STONE, true, true, false, false), + new MaterialConfigOptions(MaterialNames.WOOD, true, true, false, false), + new MaterialConfigOptions(MaterialNames.ENDER, true, true, true, true), + new MaterialConfigOptions(MaterialNames.QUARTZ, true, true, true, true), + new MaterialConfigOptions(MaterialNames.OBSIDIAN, true, true, true, true), + new MaterialConfigOptions(MaterialNames.LAPIS, true, true, false, false), + new MaterialConfigOptions(MaterialNames.PRISMARINE, true, true, true, true), + new MaterialConfigOptions(MaterialNames.REDSTONE, true, true, true, true), }; - /** - * Fired when the configuration changes. - * - * @param event The Event. - */ + /** Reloads values saved through Forge's configuration screen. */ @SubscribeEvent public void onConfigChange(final ConfigChangedEvent.OnConfigChangedEvent event) { if (event.getModID().equals(BaseMetals.MODID)) { @@ -59,22 +107,113 @@ public void onConfigChange(final ConfigChangedEvent.OnConfigChangedEvent event) } } - /** - * - */ + /** Loads defaults, preserves legacy files, and latches the content mode once per launch. */ public static void init() { if (configuration == null) { configuration = new Configuration(new File(CONFIG_FILE)); MinecraftForge.EVENT_BUS.register(new BMeConfig()); } - - // GENERAL - Options.setEnableAchievements(configuration.getBoolean("achievements", GENERAL_CAT, true, - "If false, then Base Metals Achievements will be disabled (This is currently required if you disable any metals")); - - configMaterialOptions(MATERIAL_CONFIG_OPTIONS, configuration); + populateConfiguration(configuration); + if (!contentModeLatched) { + activeContentMode = configuredContentMode(configuration); + contentModeLatched = true; + } if (configuration.hasChanged()) { configuration.save(); } } + + static void populateConfiguration(final Configuration target) { + // General settings are registered before the material-specific categories. + Options.setEnableAchievements(target.getBoolean("achievements", GENERAL_CAT, true, + "If false, then Base Metals Achievements will be disabled (This is currently required if you disable any metals")); + final Property achievements = target.getCategory(GENERAL_CAT).get("achievements"); + final Property contentMode = target.get(GENERAL_CAT, CONTENT_MODE_PROPERTY, + ContentMode.HIGH_FANTASY.serializedName(), + "Controls Base Metals acquisition: high_fantasy keeps every historical recipe; " + + "low_fantasy restricts implausible forms; realism also removes mythical materials.", + ContentMode.serializedNames()); + final String configuredValue = contentMode.getString(); + if (!ContentMode.isValidSerializedName(configuredValue)) { + LOGGER.warn("Invalid Base Metals content mode '{}'; using '{}'.", + configuredValue, ContentMode.HIGH_FANTASY.serializedName()); + contentMode.set(ContentMode.HIGH_FANTASY.serializedName()); + } + + configMaterialOptions(MATERIAL_CONFIG_OPTIONS, target); + configureGuiMetadata(target, achievements, contentMode); + } + + private static void configureGuiMetadata(final Configuration target, + final Property achievements, final Property contentMode) { + achievements.setLanguageKey("config.basemetals.option.achievements") + .setRequiresMcRestart(true); + contentMode.setLanguageKey("config.basemetals.option.content_mode") + .setValidValues(ContentMode.serializedNames()) + .setValidValuesDisplay(ContentMode.translationKeys()) + .setRequiresMcRestart(true); + + for (final String categoryName : GUI_CATEGORIES) { + final String languageSuffix = categoryName.toLowerCase(java.util.Locale.ROOT) + .replace(' ', '_'); + target.getCategory(categoryName) + .setLanguageKey("config.basemetals.category." + languageSuffix) + .setRequiresMcRestart(true); + } + + for (final MaterialConfigOptions options : MATERIAL_CONFIG_OPTIONS) { + final String identifier = options.getIdentifier(); + final String propertySuffix = WordUtils.capitalizeFully(identifier); + final String materialLanguageKey = "config.basemetals.material." + identifier; + final String category = options.getVanilla() ? VANILLA_CAT : MATERIALS_CAT; + decorate(target, category, "Enable" + propertySuffix, materialLanguageKey); + if (options.getHasFluid()) { + decorate(target, FLUIDS_CAT, "Enabled " + propertySuffix, materialLanguageKey); + } + if (options.getHasTraits()) { + decorate(target, FORCED_TRAITS_CAT, + "Force" + propertySuffix + "TraitRegistration", materialLanguageKey); + } + } + } + + private static void decorate(final Configuration target, final String category, + final String propertyName, final String languageKey) { + final Property property = target.getCategory(category).get(propertyName); + if (property == null) { + throw new IllegalStateException("Missing Base Metals configuration property " + + category + "/" + propertyName); + } + property.setLanguageKey(languageKey).setRequiresMcRestart(true); + } + + public static Configuration getConfiguration() { + if (configuration == null) { + throw new IllegalStateException("Base Metals configuration has not been initialized"); + } + return configuration; + } + + /** Returns the mode latched during mod construction. */ + public static ContentMode getActiveContentMode() { + return activeContentMode; + } + + /** Reads the effective value of a configuration, treating an absent key as High Fantasy. */ + public static ContentMode configuredContentMode(final Configuration target) { + if (target == null || !target.hasCategory(GENERAL_CAT)) { + return ContentMode.HIGH_FANTASY; + } + final Property property = target.getCategory(GENERAL_CAT).get(CONTENT_MODE_PROPERTY); + return property == null ? ContentMode.HIGH_FANTASY + : ContentMode.fromSerializedName(property.getString()); + } + + public static Map getGeneratedOreRules() { + return GENERATED_ORE_RULES; + } + + public static String getMaterialPropertyName(final String identifier) { + return "Enable" + WordUtils.capitalizeFully(identifier); + } } diff --git a/src/main/java/com/mcmoddev/basemetals/util/EventHandler.java b/src/main/java/com/mcmoddev/basemetals/util/EventHandler.java index 8c4b3a56..e21fe1aa 100644 --- a/src/main/java/com/mcmoddev/basemetals/util/EventHandler.java +++ b/src/main/java/com/mcmoddev/basemetals/util/EventHandler.java @@ -19,13 +19,6 @@ import com.mcmoddev.lib.events.MMDLibRegisterMaterials; import com.mcmoddev.lib.item.ItemMMDShield; import com.mcmoddev.lib.recipe.ShieldUpgradeRecipe; -import com.mcmoddev.lib.util.Config.Options; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.gui.GuiMainMenu; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.gui.GuiWorldSelection; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.SoundEvents; import net.minecraft.inventory.Container; @@ -40,24 +33,17 @@ import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.event.entity.living.LivingAttackEvent; import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; @EventBusSubscriber(modid=BaseMetals.MODID) public final class EventHandler { public EventHandler() { - // throw new IllegalAccessError(SharedStrings.NOT_INSTANTIABLE); } - /** - * - * @param event - */ + /** Applies durability loss when a Base Metals shield blocks damage. */ @SubscribeEvent public static void attackEvent(final LivingAttackEvent event) { final float damage = event.getAmount(); @@ -88,10 +74,7 @@ public static void attackEvent(final LivingAttackEvent event) { } } - /** - * - * @return - */ + /** Creates the two-slot crafting view used to evaluate shield upgrades at an anvil. */ @Nonnull public static InventoryCrafting getDummyCraftingInv() { final Container tempContainer = new Container() { @@ -104,10 +87,7 @@ public boolean canInteractWith(final EntityPlayer player) { return new InventoryCrafting(tempContainer, 2, 1); } - /** - * - * @param event - */ + /** Converts a matching shield-upgrade recipe into an anvil result and level cost. */ @SubscribeEvent public static void handleAnvilEvent(final AnvilUpdateEvent event) { final ItemStack left = event.getLeft(); @@ -129,55 +109,6 @@ public static void handleAnvilEvent(final AnvilUpdateEvent event) { } } - /** - * - * @param event - */ - @SideOnly(Side.CLIENT) - @SubscribeEvent - public static void onUpdate(final TickEvent.RenderTickEvent event) { - if ((Options.requireMMDOreSpawn()) && (Loader.isModLoaded("orespawn"))) { - return; - } - - if (!Options.fallbackOrespawn()) { - return; - } - - if (!Options.requireMMDOreSpawn()) { - return; - } - - final Minecraft minecraft = Minecraft.getMinecraft(); - final GuiScreen guiscreen = minecraft.currentScreen; - if (guiscreen == null) { - return; - } - final FontRenderer fontRender = minecraft.fontRenderer; - final int y = (guiscreen.height / 100) * 2; - int x = (guiscreen.width / 2); - - if (guiscreen instanceof GuiMainMenu) { - guiscreen.drawCenteredString(fontRender, - "MMD OreSpawn not present, but requested in configuration, using fallback generator!", - x, y, 0xffffff00); - } else if (guiscreen instanceof GuiWorldSelection) { - x = 10; - final int widest = fontRender.getStringWidth( - "This is likely not what you want - try turning off the 'using_orespawn' option"); - final int shortest = fontRender.getStringWidth("Fallback Ore Spawn Generator Enabled!"); - int wrap = widest + 50; - - if ((guiscreen.width / 2) <= wrap) { - wrap = shortest + 50; - } - - fontRender.drawSplitString( - "Fallback Ore Spawn Generator Enabled!\nThis is likely not what you want - try turning off the 'using_orespawn' option\n(or install MMD OreSpawn)", - x, y, wrap, 0xFFFFFF00); - } - } - @SubscribeEvent public static void mmdlibRegisterMaterials(final MMDLibRegisterMaterials event) { com.mcmoddev.basemetals.init.Materials.init(event); diff --git a/src/main/java/com/mcmoddev/basemetals/util/VillagerTradeHelper.java b/src/main/java/com/mcmoddev/basemetals/util/VillagerTradeHelper.java index 1b6807f5..1be733ad 100644 --- a/src/main/java/com/mcmoddev/basemetals/util/VillagerTradeHelper.java +++ b/src/main/java/com/mcmoddev/basemetals/util/VillagerTradeHelper.java @@ -6,11 +6,7 @@ import net.minecraftforge.fml.common.registry.VillagerRegistry.VillagerCareer; import net.minecraftforge.fml.common.registry.VillagerRegistry.VillagerProfession; -/** - * Helper for Villager Trades. - * - * @author Chris on 3/30/2016. - */ +/** Adds trades to Forge's registered vanilla villager careers. */ public final class VillagerTradeHelper { private static final ResourceLocation[] professionList = { @@ -23,8 +19,8 @@ protected VillagerTradeHelper() { } /** - * Inserts one or more trades to the default villager trade table using dark magic (aka java - * reflection). + * Inserts trades by resolving the vanilla profession ID, then delegates to the + * resource-location overload. * * @param professionID * Villager profession ID (0-4) diff --git a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBitsRegistryEvents.java b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBitsRegistryEvents.java index 01a1dc68..7f9afcd1 100755 --- a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBitsRegistryEvents.java +++ b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBitsRegistryEvents.java @@ -14,7 +14,6 @@ import net.minecraft.client.renderer.block.model.ModelBakery; import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.item.Item; -import net.minecraft.item.crafting.IRecipe; import net.minecraft.util.ResourceLocation; import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.model.ModelLoader; @@ -85,8 +84,4 @@ public static void modelRegistryBits(ModelRegistryEvent ev) { }); } - @SubscribeEvent - public static void registerRecipes(RegistryEvent.Register ev) { - // do nothing, as we have nothing to do - } } diff --git a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBlocks.java b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBlocks.java index 910e87f5..ff2ab325 100755 --- a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBlocks.java +++ b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBlocks.java @@ -13,6 +13,7 @@ import com.mcmoddev.lib.util.Config.Options; import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @Mod.EventBusSubscriber(modid=BaseMetals.MODID) @@ -22,13 +23,53 @@ private VanillaBlocks() { throw new IllegalAccessError("Class cannot be instantiated!"); } - @SubscribeEvent + @SubscribeEvent(priority=EventPriority.HIGHEST) public static void registerVanilla(MMDLibRegisterBlocks ev) { - // Vanilla Materials get their Ore and Block always + // Reuse vanilla ore and storage blocks so integrations resolve one canonical form. final MMDMaterial charcoal = Materials.getMaterialByName(MaterialNames.CHARCOAL); + final MMDMaterial coal = Materials.getMaterialByName(MaterialNames.COAL); + final MMDMaterial diamond = Materials.getMaterialByName(MaterialNames.DIAMOND); + final MMDMaterial emerald = Materials.getMaterialByName(MaterialNames.EMERALD); final MMDMaterial gold = Materials.getMaterialByName(MaterialNames.GOLD); final MMDMaterial iron = Materials.getMaterialByName(MaterialNames.IRON); + final MMDMaterial lapis = Materials.getMaterialByName(MaterialNames.LAPIS); + final MMDMaterial obsidian = Materials.getMaterialByName(MaterialNames.OBSIDIAN); final MMDMaterial quartz = Materials.getMaterialByName(MaterialNames.QUARTZ); + final MMDMaterial redstone = Materials.getMaterialByName(MaterialNames.REDSTONE); + + coal.addNewBlock(Names.BLOCK, net.minecraft.init.Blocks.COAL_BLOCK); + coal.addNewBlock(Names.ORE, net.minecraft.init.Blocks.COAL_ORE); + + diamond.addNewBlock(Names.BLOCK, net.minecraft.init.Blocks.DIAMOND_BLOCK); + diamond.addNewBlock(Names.ORE, net.minecraft.init.Blocks.DIAMOND_ORE); + + emerald.addNewBlock(Names.BLOCK, net.minecraft.init.Blocks.EMERALD_BLOCK); + emerald.addNewBlock(Names.ORE, net.minecraft.init.Blocks.EMERALD_ORE); + + gold.addNewBlock(Names.BLOCK, net.minecraft.init.Blocks.GOLD_BLOCK); + gold.addNewBlock(Names.ORE, net.minecraft.init.Blocks.GOLD_ORE); + gold.addNewBlock(Names.PRESSURE_PLATE, + net.minecraft.init.Blocks.LIGHT_WEIGHTED_PRESSURE_PLATE); + + iron.addNewBlock(Names.BLOCK, net.minecraft.init.Blocks.IRON_BLOCK); + iron.addNewBlock(Names.ORE, net.minecraft.init.Blocks.IRON_ORE); + iron.addNewBlock(Names.BARS, net.minecraft.init.Blocks.IRON_BARS); + iron.addNewBlock(Names.DOOR, net.minecraft.init.Blocks.IRON_DOOR); + iron.addNewBlock(Names.TRAPDOOR, net.minecraft.init.Blocks.IRON_TRAPDOOR); + iron.addNewBlock(Names.PRESSURE_PLATE, + net.minecraft.init.Blocks.HEAVY_WEIGHTED_PRESSURE_PLATE); + + lapis.addNewBlock(Names.BLOCK, net.minecraft.init.Blocks.LAPIS_BLOCK); + lapis.addNewBlock(Names.ORE, net.minecraft.init.Blocks.LAPIS_ORE); + + obsidian.addNewBlock(Names.BLOCK, net.minecraft.init.Blocks.OBSIDIAN); + + quartz.addNewBlock(Names.BLOCK, net.minecraft.init.Blocks.QUARTZ_BLOCK); + quartz.addNewBlock(Names.ORE, net.minecraft.init.Blocks.QUARTZ_ORE); + quartz.addNewBlock(Names.STAIRS, net.minecraft.init.Blocks.QUARTZ_STAIRS); + + redstone.addNewBlock(Names.BLOCK, net.minecraft.init.Blocks.REDSTONE_BLOCK); + redstone.addNewBlock(Names.ORE, net.minecraft.init.Blocks.REDSTONE_ORE); if (Materials.hasMaterial(MaterialNames.CHARCOAL)) { create(Names.BLOCK, charcoal); diff --git a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaFluids.java b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaFluids.java index 05844bee..b12d210f 100755 --- a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaFluids.java +++ b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaFluids.java @@ -16,7 +16,7 @@ public class VanillaFluids extends Fluids { @SubscribeEvent(priority=EventPriority.HIGHEST) public static void registerFluids(MMDLibRegisterFluids ev) { - // Vanilla Materials need to always have fluids available in case of tie-in mods + // Integration mods may need these fluids even when Base Metals adds no matching equipment. Arrays.asList(MaterialNames.CHARCOAL, MaterialNames.COAL, MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.ENDER, MaterialNames.GOLD, MaterialNames.IRON, MaterialNames.LAPIS, diff --git a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaItems.java b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaItems.java index 474f916b..ffc2aa45 100755 --- a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaItems.java +++ b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaItems.java @@ -5,6 +5,7 @@ import javax.annotation.Nonnull; import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.init.Items; import com.mcmoddev.lib.data.Names; import com.mcmoddev.lib.data.MaterialNames; import com.mcmoddev.lib.events.MMDLibRegisterItems; @@ -13,18 +14,33 @@ import com.mcmoddev.lib.material.MMDMaterial; import com.mcmoddev.lib.util.Config.Options; +import net.minecraft.item.ItemStack; import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @Mod.EventBusSubscriber(modid=BaseMetals.MODID) public class VanillaItems extends com.mcmoddev.lib.init.Items { private VanillaItems() { - // TODO Auto-generated constructor stub } - @SubscribeEvent + @SubscribeEvent(priority=EventPriority.HIGHEST) public static void registerItemsEvent(MMDLibRegisterItems ev) { + Materials.getMaterialByName(MaterialNames.CHARCOAL).addNewItemFromItemStack(Names.INGOT, + new ItemStack(net.minecraft.init.Items.COAL, 1, 1)); + Materials.getMaterialByName(MaterialNames.COAL).addNewItemFromItemStack(Names.INGOT, + new ItemStack(net.minecraft.init.Items.COAL, 1, 0)); + + Materials.getMaterialByName(MaterialNames.EMERALD).addNewItem(Names.INGOT, + net.minecraft.init.Items.EMERALD); + Materials.getMaterialByName(MaterialNames.LAPIS).addNewItemFromItemStack(Names.INGOT, + new ItemStack(net.minecraft.init.Items.DYE, 1, 4)); + Materials.getMaterialByName(MaterialNames.QUARTZ).addNewItem(Names.INGOT, + net.minecraft.init.Items.QUARTZ); + Materials.getMaterialByName(MaterialNames.REDSTONE).addNewItem(Names.POWDER, + net.minecraft.init.Items.REDSTONE); + addDiamondBits(); addGoldBits(); addIronBits(); @@ -32,16 +48,22 @@ public static void registerItemsEvent(MMDLibRegisterItems ev) { addWoodBits(); doSpecialMats(); - // these three are the only ones that need tools and armor + // Emerald, obsidian, and quartz receive the vanilla-style tool and armor set. Arrays.asList(MaterialNames.EMERALD, MaterialNames.OBSIDIAN, MaterialNames.QUARTZ) .stream().map(Materials::getMaterialByName) .filter(mat -> Options.isMaterialEnabled(mat.toString())) .forEach(material -> Arrays.asList(Names.AXE, Names.BOOTS, Names.CHESTPLATE, Names.HELMET, Names.HOE, Names.LEGGINGS, Names.PICKAXE, Names.SHOVEL, Names.HORSE_ARMOR) .stream() - .filter(n -> !material.hasItem(n)).forEach(n -> create(n, material))); + .filter(n -> !material.hasItem(n)).forEach(n -> { + if (n == Names.HOE) { + Items.createHoe(material); + } else { + create(n, material); + } + })); - // shields + // These solid vanilla materials support the shared equipment and building forms. Arrays.asList(MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.GOLD, MaterialNames.IRON, MaterialNames.OBSIDIAN, MaterialNames.QUARTZ) .stream().map(Materials::getMaterialByName) @@ -50,9 +72,21 @@ public static void registerItemsEvent(MMDLibRegisterItems ev) { Names.CROSSBOW, Names.FISHING_ROD, Names.ROD, Names.BARS, Names.SHEARS, Names.BUTTON, Names.SWORD, Names.SHIELD, Names.DOOR, Names.SLAB) .stream() - .filter(n -> !material.hasItem(n)).forEach(n -> create(n, material))); + .filter(n -> !material.hasItem(n)).forEach(n -> { + if (n == Names.ARROW) { + Items.createArrow(material); + } else if (n == Names.BOLT) { + Items.createBolt(material); + } else if (n == Names.BOW) { + Items.createBow(material); + } else if (n == Names.CROSSBOW) { + Items.createCrossbow(material); + } else { + create(n, material); + } + })); - // bits that everything should have + // Crackhammers, gears, and scythes also make sense for stone and wood. Arrays.asList(MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.GOLD, MaterialNames.IRON, MaterialNames.OBSIDIAN, MaterialNames.QUARTZ, MaterialNames.STONE, MaterialNames.WOOD) @@ -62,7 +96,7 @@ public static void registerItemsEvent(MMDLibRegisterItems ev) { Names.SCYTHE).stream() .filter(n -> !material.hasItem(n)).forEach(n -> create(n, material))); - // last few bits + // Powders and nuggets are available only where a meaningful source item exists. Arrays.asList(MaterialNames.COAL, MaterialNames.CHARCOAL, MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.GOLD, MaterialNames.IRON, MaterialNames.OBSIDIAN, MaterialNames.REDSTONE, @@ -80,7 +114,7 @@ public static void registerItemsEvent(MMDLibRegisterItems ev) { .map(Materials::getMaterialByName) .filter(m -> !m.hasItem(Names.NUGGET)).forEach(material -> create(Names.NUGGET, material)); - //these bits just are too... specialized to fit the iteration above + // These one-off forms do not share a useful material group. if(Options.isMaterialEnabled(MaterialNames.STONE)) { create(Names.ROD, Materials.getMaterialByName(MaterialNames.STONE)); } @@ -108,7 +142,7 @@ private static void setBurnTimes(@Nonnull final MMDMaterial material) { ((IMMDBurnableObject) material.getItem(Names.SMALLPOWDER)).setBurnTime(NUGGET_BURN_TIME); } - // simple hack to fix this shit - I give up on trying for more + // MMDLib stores a block's fuel value on its ItemBlock rather than the block. if (material.hasBlock(Names.BLOCK) && material.getName().equals(MaterialNames.CHARCOAL)) { ((IMMDBurnableObject) material.getItem("ItemBlock_charcoal_block")).setBurnTime(BLOCK_BURN_TIME); } @@ -155,6 +189,18 @@ private static void doSpecialMats() { private static void addDiamondBits() { final MMDMaterial diamond = Materials.getMaterialByName(MaterialNames.DIAMOND); + diamond.addNewItem(Names.AXE, net.minecraft.init.Items.DIAMOND_AXE); + diamond.addNewItem(Names.HOE, net.minecraft.init.Items.DIAMOND_HOE); + diamond.addNewItem(Names.HORSE_ARMOR, net.minecraft.init.Items.DIAMOND_HORSE_ARMOR); + diamond.addNewItem(Names.PICKAXE, net.minecraft.init.Items.DIAMOND_PICKAXE); + diamond.addNewItem(Names.SHOVEL, net.minecraft.init.Items.DIAMOND_SHOVEL); + diamond.addNewItem(Names.SWORD, net.minecraft.init.Items.DIAMOND_SWORD); + diamond.addNewItem(Names.BOOTS, net.minecraft.init.Items.DIAMOND_BOOTS); + diamond.addNewItem(Names.CHESTPLATE, net.minecraft.init.Items.DIAMOND_CHESTPLATE); + diamond.addNewItem(Names.HELMET, net.minecraft.init.Items.DIAMOND_HELMET); + diamond.addNewItem(Names.LEGGINGS, net.minecraft.init.Items.DIAMOND_LEGGINGS); + diamond.addNewItem(Names.INGOT, net.minecraft.init.Items.DIAMOND); + if (Materials.hasMaterial(MaterialNames.DIAMOND)) { create(Names.BLEND, diamond); create(Names.NUGGET, diamond); @@ -162,11 +208,11 @@ private static void addDiamondBits() { create(Names.SMALLBLEND, diamond); create(Names.SMALLPOWDER, diamond); - create(Names.ARROW, diamond); - create(Names.BOLT, diamond); - create(Names.BOW, diamond); + Items.createArrow(diamond); + Items.createBolt(diamond); + Items.createBow(diamond); create(Names.CRACKHAMMER, diamond); - create(Names.CROSSBOW, diamond); + Items.createCrossbow(diamond); create(Names.DOOR, diamond); create(Names.FISHING_ROD, diamond); create(Names.SHEARS, diamond); @@ -181,17 +227,30 @@ private static void addDiamondBits() { private static void addGoldBits() { final MMDMaterial gold = Materials.getMaterialByName(MaterialNames.GOLD); + gold.addNewItem(Names.AXE, net.minecraft.init.Items.GOLDEN_AXE); + gold.addNewItem(Names.HOE, net.minecraft.init.Items.GOLDEN_HOE); + gold.addNewItem(Names.HORSE_ARMOR, net.minecraft.init.Items.GOLDEN_HORSE_ARMOR); + gold.addNewItem(Names.PICKAXE, net.minecraft.init.Items.GOLDEN_PICKAXE); + gold.addNewItem(Names.SHOVEL, net.minecraft.init.Items.GOLDEN_SHOVEL); + gold.addNewItem(Names.SWORD, net.minecraft.init.Items.GOLDEN_SWORD); + gold.addNewItem(Names.BOOTS, net.minecraft.init.Items.GOLDEN_BOOTS); + gold.addNewItem(Names.CHESTPLATE, net.minecraft.init.Items.GOLDEN_CHESTPLATE); + gold.addNewItem(Names.HELMET, net.minecraft.init.Items.GOLDEN_HELMET); + gold.addNewItem(Names.LEGGINGS, net.minecraft.init.Items.GOLDEN_LEGGINGS); + gold.addNewItem(Names.INGOT, net.minecraft.init.Items.GOLD_INGOT); + gold.addNewItem(Names.NUGGET, net.minecraft.init.Items.GOLD_NUGGET); + if (Materials.hasMaterial(MaterialNames.GOLD)) { create(Names.BLEND, gold); create(Names.POWDER, gold); create(Names.SMALLBLEND, gold); create(Names.SMALLPOWDER, gold); - create(Names.ARROW, gold); - create(Names.BOLT, gold); - create(Names.BOW, gold); + Items.createArrow(gold); + Items.createBolt(gold); + Items.createBow(gold); create(Names.CRACKHAMMER, gold); - create(Names.CROSSBOW, gold); + Items.createCrossbow(gold); create(Names.DOOR, gold); create(Names.FISHING_ROD, gold); create(Names.SHEARS, gold); @@ -206,6 +265,21 @@ private static void addGoldBits() { private static void addIronBits() { final MMDMaterial iron = Materials.getMaterialByName(MaterialNames.IRON); + iron.addNewItem(Names.AXE, net.minecraft.init.Items.IRON_AXE); + iron.addNewItem(Names.DOOR, net.minecraft.init.Items.IRON_DOOR); + iron.addNewItem(Names.HOE, net.minecraft.init.Items.IRON_HOE); + iron.addNewItem(Names.HORSE_ARMOR, net.minecraft.init.Items.IRON_HORSE_ARMOR); + iron.addNewItem(Names.PICKAXE, net.minecraft.init.Items.IRON_PICKAXE); + iron.addNewItem(Names.SHOVEL, net.minecraft.init.Items.IRON_SHOVEL); + iron.addNewItem(Names.SWORD, net.minecraft.init.Items.IRON_SWORD); + iron.addNewItem(Names.BOOTS, net.minecraft.init.Items.IRON_BOOTS); + iron.addNewItem(Names.CHESTPLATE, net.minecraft.init.Items.IRON_CHESTPLATE); + iron.addNewItem(Names.HELMET, net.minecraft.init.Items.IRON_HELMET); + iron.addNewItem(Names.LEGGINGS, net.minecraft.init.Items.IRON_LEGGINGS); + iron.addNewItem(Names.INGOT, net.minecraft.init.Items.IRON_INGOT); + iron.addNewItem(Names.NUGGET, net.minecraft.init.Items.IRON_NUGGET); + iron.addNewItem(Names.SHEARS, net.minecraft.init.Items.SHEARS); + if (Materials.hasMaterial(MaterialNames.IRON)) { create(Names.BLEND, iron); create(Names.INGOT, iron); @@ -214,14 +288,14 @@ private static void addIronBits() { create(Names.SMALLBLEND, iron); create(Names.SMALLPOWDER, iron); - create(Names.ARROW, iron); + Items.createArrow(iron); create(Names.AXE, iron); - create(Names.BOLT, iron); + Items.createBolt(iron); create(Names.BOOTS, iron); - create(Names.BOW, iron); + Items.createBow(iron); create(Names.CHESTPLATE, iron); create(Names.CRACKHAMMER, iron); - create(Names.CROSSBOW, iron); + Items.createCrossbow(iron); create(Names.FISHING_ROD, iron); create(Names.HELMET, iron); create(Names.HOE, iron); @@ -242,6 +316,16 @@ private static void addIronBits() { private static void addStoneBits() { final MMDMaterial stone = Materials.getMaterialByName(MaterialNames.STONE); + stone.addNewItem(Names.AXE, net.minecraft.init.Items.STONE_AXE); + stone.addNewItem(Names.HOE, net.minecraft.init.Items.STONE_HOE); + stone.addNewItem(Names.PICKAXE, net.minecraft.init.Items.STONE_PICKAXE); + stone.addNewItem(Names.SHOVEL, net.minecraft.init.Items.STONE_SHOVEL); + stone.addNewItem(Names.SWORD, net.minecraft.init.Items.STONE_SWORD); + stone.addNewBlock(Names.BLOCK, net.minecraft.init.Blocks.STONE); + stone.addNewBlock(Names.SLAB, net.minecraft.init.Blocks.STONE_SLAB); + stone.addNewBlock(Names.DOUBLE_SLAB, net.minecraft.init.Blocks.DOUBLE_STONE_SLAB); + stone.addNewBlock(Names.STAIRS, net.minecraft.init.Blocks.STONE_STAIRS); + if (Materials.hasMaterial(MaterialNames.STONE)) { create(Names.CRACKHAMMER, stone); create(Names.ROD, stone); @@ -253,6 +337,21 @@ private static void addStoneBits() { private static void addWoodBits() { final MMDMaterial wood = Materials.getMaterialByName(MaterialNames.WOOD); + wood.addNewItem(Names.AXE, net.minecraft.init.Items.WOODEN_AXE); + wood.addNewItem(Names.DOOR, net.minecraft.init.Items.OAK_DOOR); + wood.addNewItem(Names.HOE, net.minecraft.init.Items.WOODEN_HOE); + wood.addNewItem(Names.PICKAXE, net.minecraft.init.Items.WOODEN_PICKAXE); + wood.addNewItem(Names.SHOVEL, net.minecraft.init.Items.WOODEN_SHOVEL); + wood.addNewItem(Names.SWORD, net.minecraft.init.Items.WOODEN_SWORD); + wood.addNewBlock(Names.DOOR, net.minecraft.init.Blocks.OAK_DOOR); + wood.addNewBlock(Names.ORE, net.minecraft.init.Blocks.LOG); + wood.addNewBlock(Names.TRAPDOOR, net.minecraft.init.Blocks.TRAPDOOR); + wood.addNewBlock(Names.BLOCK, net.minecraft.init.Blocks.PLANKS); + wood.addNewBlock(Names.SLAB, net.minecraft.init.Blocks.WOODEN_SLAB); + wood.addNewBlock(Names.DOUBLE_SLAB, net.minecraft.init.Blocks.DOUBLE_WOODEN_SLAB); + wood.addNewBlock(Names.STAIRS, net.minecraft.init.Blocks.OAK_STAIRS); + wood.addNewItem(Names.SHEARS, net.minecraft.init.Items.SHEARS); + if (Materials.hasMaterial(MaterialNames.WOOD)) { create(Names.CRACKHAMMER, wood); create(Names.GEAR, wood); diff --git a/src/main/java/com/mcmoddev/basemetals/vanillabits/package-info.java b/src/main/java/com/mcmoddev/basemetals/vanillabits/package-info.java index be4b2226..811dbba3 100755 --- a/src/main/java/com/mcmoddev/basemetals/vanillabits/package-info.java +++ b/src/main/java/com/mcmoddev/basemetals/vanillabits/package-info.java @@ -1,8 +1,2 @@ -/** - * - */ -/** - * @author madman - * - */ -package com.mcmoddev.basemetals.vanillabits; \ No newline at end of file +/** Adds Base Metals forms and recipes for vanilla materials. */ +package com.mcmoddev.basemetals.vanillabits; diff --git a/src/main/java/com/mcmoddev/basemetals/worldgen/BaseMetalsWorldgenProvider.java b/src/main/java/com/mcmoddev/basemetals/worldgen/BaseMetalsWorldgenProvider.java new file mode 100644 index 00000000..6d81c21a --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/worldgen/BaseMetalsWorldgenProvider.java @@ -0,0 +1,92 @@ +package com.mcmoddev.basemetals.worldgen; + +import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.basemetals.content.ContentPolicy; +import com.mcmoddev.basemetals.data.MaterialNames; +import net.minecraft.util.ResourceLocation; +import zone.moddev.mc.orespawn.api.OreDimensionSelector; +import zone.moddev.mc.orespawn.api.OreHeightDistribution; +import zone.moddev.mc.orespawn.api.OrePattern; +import zone.moddev.mc.orespawn.api.OreSpawnApi; +import zone.moddev.mc.orespawn.api.WorldgenProvider; + +/** Builds Base Metals' OreSpawn defaults from the startup-latched content mode. */ +public final class BaseMetalsWorldgenProvider { + public static final int PROVIDER_REVISION = 2; + private static final ResourceLocation NETHER = id("minecraft", "the_nether"); + private static final ResourceLocation END = id("minecraft", "the_end"); + private static final ResourceLocation STONE = id("minecraft", "stone"); + private static final ResourceLocation NETHERRACK = id("minecraft", "netherrack"); + private static final ResourceLocation END_STONE = id("minecraft", "end_stone"); + + private BaseMetalsWorldgenProvider() { + } + + public static boolean enqueue() { + return OreSpawnApi.enqueue(build(ContentPolicy.active())); + } + + public static WorldgenProvider build(final ContentPolicy policy) { + final WorldgenProvider.Builder provider = WorldgenProvider + .builder(BaseMetals.MODID, PROVIDER_REVISION) + .mergeNewEntriesIntoExistingWorlds(true); + + addDimensionOre(provider, policy, MaterialNames.COLDIRON, NETHER, 0, 127, 5.0D); + addDimensionOre(provider, policy, MaterialNames.ADAMANTINE, NETHER, 0, 127, 2.0D); + addDimensionOre(provider, policy, MaterialNames.STARSTEEL, END, 0, 254, 5.0D); + addOrdinaryOre(provider, policy, MaterialNames.COPPER, 0, 95, 10.0D); + addOrdinaryOre(provider, policy, MaterialNames.SILVER, 0, 31, 4.0D); + addOrdinaryOre(provider, policy, MaterialNames.TIN, 0, 127, 10.0D); + addOrdinaryOre(provider, policy, MaterialNames.LEAD, 0, 63, 5.0D); + addOrdinaryOre(provider, policy, MaterialNames.ZINC, 0, 95, 5.0D); + addOrdinaryOre(provider, policy, MaterialNames.MERCURY, 0, 31, 3.0D); + addOrdinaryOre(provider, policy, MaterialNames.NICKEL, 32, 95, 1.0D); + addOrdinaryOre(provider, policy, MaterialNames.PLATINUM, 1, 31, 0.125D); + return provider.build(); + } + + private static void addDimensionOre(final WorldgenProvider.Builder provider, + final ContentPolicy policy, final String material, final ResourceLocation dimension, + final int minY, final int maxY, final double attempts) { + final ResourceLocation block = id(BaseMetals.MODID, material + "_ore"); + provider.ore(id(BaseMetals.MODID, "legacy/" + material + "_ore"), block, ore -> ore + .enabled(policy.defaultsOreEnabled(material)) + .nativeGeneration(false) + .retrogen(false) + .output(block, 100.0D) + .dimension(dimension, placement -> configure(placement, minY, maxY, attempts))); + } + + private static void addOrdinaryOre(final WorldgenProvider.Builder provider, + final ContentPolicy policy, final String material, final int minY, + final int maxY, final double attempts) { + final ResourceLocation block = id(BaseMetals.MODID, material + "_ore"); + provider.ore(id(BaseMetals.MODID, "legacy/" + material + "_ore"), block, ore -> ore + .enabled(policy.defaultsOreEnabled(material)) + .nativeGeneration(false) + .retrogen(false) + .output(block, 100.0D) + .dimensionSelector(OreDimensionSelector.ALL_EXCEPT_NETHER_AND_END, + placement -> configure(placement, minY, maxY, attempts))); + } + + private static void configure(final WorldgenProvider.OreDimensionDefinition.Builder placement, + final int minY, final int maxY, final double attempts) { + placement.enabled(true) + .yRange(minY, maxY) + .attempts(attempts) + .quantityRange(4, 11) + .pattern(OrePattern.DEFAULT) + .heightDistribution(OreHeightDistribution.UNIFORM) + .discardChanceOnAirExposure(0.0D) + .spread(8, 4) + .nodeSize(8) + .hostBlock(STONE) + .hostBlock(NETHERRACK) + .hostBlock(END_STONE); + } + + private static ResourceLocation id(final String namespace, final String path) { + return new ResourceLocation(namespace, path); + } +} diff --git a/src/main/java/com/mcmoddev/orespawn/package-info.java b/src/main/java/com/mcmoddev/orespawn/package-info.java deleted file mode 100644 index 941e2ea1..00000000 --- a/src/main/java/com/mcmoddev/orespawn/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@ParametersAreNonnullByDefault -package com.mcmoddev.orespawn; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/resources/assets/basemetals/advancements/recipes/transportation/rail.json b/src/main/resources/assets/basemetals/advancements/recipes/transportation/rail.json new file mode 100644 index 00000000..98d795da --- /dev/null +++ b/src/main/resources/assets/basemetals/advancements/recipes/transportation/rail.json @@ -0,0 +1,44 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "minecraft:rail", + "basemetals:rail" + ] + }, + "criteria": { + "has_iron_ingot": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "minecraft:iron_ingot" + } + ] + } + }, + "has_steel_ingot": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "basemetals:steel_ingot" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:rail" + } + } + }, + "requirements": [ + [ + "has_iron_ingot", + "has_steel_ingot", + "has_the_recipe" + ] + ] +} diff --git a/src/main/resources/assets/basemetals/alt/chests/abandoned_mineshaft.json b/src/main/resources/assets/basemetals/alt/chests/abandoned_mineshaft.json index 443e7f69..d8f1a7a3 100644 --- a/src/main/resources/assets/basemetals/alt/chests/abandoned_mineshaft.json +++ b/src/main/resources/assets/basemetals/alt/chests/abandoned_mineshaft.json @@ -1,380 +1,658 @@ { - "pools": [ + "pools": [ + { + "__comment": "25% chance per roll of common metal ingots", + "rolls": { + "min": 1, + "max": 4 + }, + "bonus_rolls": 1, + "entries": [ { - "__comment":"25% chance per roll of common metal ingots", - "rolls": { + "type": "empty", + "weight": 63 + }, + { + "type": "item", + "name": "minecraft:iron_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:lead_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { "min": 1, - "max": 4 - }, - "bonus_rolls":1, - "entries": [ - { - "type": "empty", - "weight": 63 - }, - { - "type": "item", - "name": "minecraft:iron_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:tin_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:lead_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:zinc_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:copper_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:brass_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - } - ] - }, - { - "__comment":"25% chance of a common-metal tool", - "rolls": 1, - "entries": [ - { - "type": "empty", - "weight": 450 - }, - { - "type": "item", - "name": "minecraft:iron_axe", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_boots", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:iron_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:tin_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:copper_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:bronze_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:steel_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_crackhammer", - "weight": 3 - } - ] + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:lead_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:zinc_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:zinc_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:brass_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:brass_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_ingot" + } + ] + } + ] + }, + { + "__comment": "25% chance of a common-metal tool", + "rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 450 + }, + { + "type": "item", + "name": "minecraft:iron_axe", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_boots", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_chestplate", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_helmet", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_hoe", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_leggings", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_pickaxe", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_shovel", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_sword", + "weight": 3 + }, + { + "type": "item", + "name": "basemetals:iron_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:iron_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_crackhammer" + } + ] } - ] + ] + } + ] } diff --git a/src/main/resources/assets/basemetals/alt/chests/desert_pyramid.json b/src/main/resources/assets/basemetals/alt/chests/desert_pyramid.json index fb03bda5..8cd379bc 100644 --- a/src/main/resources/assets/basemetals/alt/chests/desert_pyramid.json +++ b/src/main/resources/assets/basemetals/alt/chests/desert_pyramid.json @@ -1,678 +1,1068 @@ { - "pools": [ - { - "__comment":"25% chance of an uncommon metal tool", - "rolls": 1, - "entries": [ - { - "type": "empty", - "weight": 900 - }, - { - "type": "item", - "name": "minecraft:iron_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:iron_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:bronze_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:steel_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:invar_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:coldiron_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:mithril_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:aquarium_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_crackhammer", - "weight": 3 - } - ] - }, - { - "__comment":"20% chance per roll of uncommon metal ingots", - "rolls": { + "pools": [ + { + "__comment": "25% chance of an uncommon metal tool", + "rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 900 + }, + { + "type": "item", + "name": "minecraft:iron_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "basemetals:iron_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:iron_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_crackhammer" + } + ] + } + ] + }, + { + "__comment": "20% chance per roll of uncommon metal ingots", + "rolls": { + "min": 1, + "max": 2 + }, + "bonus_rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 72 + }, + { + "type": "item", + "name": "minecraft:gold_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ] + }, + { + "type": "item", + "name": "basemetals:silver_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:silver_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:nickel_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:nickel_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:electrum_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:electrum_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 3, + "max": 12 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { "min": 1, - "max": 2 - }, - "bonus_rolls":1, - "entries": [ - { - "type": "empty", - "weight": 72 - }, - { - "type": "item", - "name": "minecraft:gold_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:silver_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:nickel_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:electrum_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 3, - "max": 12 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:invar_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - } - ] + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_ingot" + } + ] } - ] + ] + } + ] } diff --git a/src/main/resources/assets/basemetals/alt/chests/end_city_treasure.json b/src/main/resources/assets/basemetals/alt/chests/end_city_treasure.json index 3cf8f516..1e4f3a68 100644 --- a/src/main/resources/assets/basemetals/alt/chests/end_city_treasure.json +++ b/src/main/resources/assets/basemetals/alt/chests/end_city_treasure.json @@ -1,693 +1,1084 @@ { - "pools": [ - { - "__comment":"25% chance of a rare metal tool", - "rolls": 1, - "entries": [ - { - "type": "empty", - "weight": 540 - }, - { - "type": "item", - "name": "basemetals:invar_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:invar_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:invar_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:invar_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:invar_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:invar_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:invar_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:invar_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:invar_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:invar_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:coldiron_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:coldiron_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:coldiron_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:coldiron_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:coldiron_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:coldiron_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:coldiron_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:coldiron_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:coldiron_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:coldiron_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:mithril_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:mithril_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:mithril_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:mithril_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:mithril_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:mithril_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:mithril_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:mithril_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:mithril_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:mithril_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:aquarium_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:aquarium_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:aquarium_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:aquarium_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:aquarium_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:aquarium_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:aquarium_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:aquarium_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:aquarium_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:aquarium_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 20, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:adamantine_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:adamantine_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:adamantine_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:adamantine_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:adamantine_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:adamantine_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:adamantine_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:adamantine_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:adamantine_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:adamantine_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:starsteel_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:starsteel_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:starsteel_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:starsteel_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:starsteel_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:starsteel_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:starsteel_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:starsteel_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:starsteel_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:starsteel_crackhammer", - "weight": 3 - } - ] - }, - { - "__comment":"25% chance of rare metal ingots", - "rolls": 1, - "entries": [ - { - "type": "empty", - "weight": 300 - }, - { - "type": "item", - "name": "basemetals:coldiron_ingot", - "weight": 40, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:aquarium_ingot", - "weight": 25, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:mithril_ingot", - "weight": 20, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:platinum_ingot", - "weight": 10, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:adamantine_ingot", - "weight": 10, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:starsteel_ingot", - "weight": 5, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - } - ] + "pools": [ + { + "__comment": "25% chance of a rare metal tool", + "rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 540 + }, + { + "type": "item", + "name": "basemetals:invar_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 20, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:adamantine_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:adamantine_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:adamantine_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:adamantine_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:adamantine_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:adamantine_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:adamantine_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:adamantine_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:adamantine_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:adamantine_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:adamantine_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:adamantine_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:adamantine_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:adamantine_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:adamantine_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:adamantine_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:adamantine_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:adamantine_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:adamantine_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:adamantine_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:starsteel_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:starsteel_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:starsteel_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:starsteel_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:starsteel_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:starsteel_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:starsteel_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:starsteel_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:starsteel_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:starsteel_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:starsteel_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:starsteel_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:starsteel_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:starsteel_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:starsteel_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:starsteel_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:starsteel_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:starsteel_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:starsteel_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:starsteel_crackhammer" + } + ] + } + ] + }, + { + "__comment": "25% chance of rare metal ingots", + "rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 300 + }, + { + "type": "item", + "name": "basemetals:coldiron_ingot", + "weight": 40, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_ingot", + "weight": 25, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_ingot", + "weight": 20, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:platinum_ingot", + "weight": 10, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:platinum_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:adamantine_ingot", + "weight": 10, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:adamantine_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:starsteel_ingot", + "weight": 5, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:starsteel_ingot" + } + ] } - ] + ] + } + ] } diff --git a/src/main/resources/assets/basemetals/alt/chests/jungle_temple.json b/src/main/resources/assets/basemetals/alt/chests/jungle_temple.json index fb03bda5..8cd379bc 100644 --- a/src/main/resources/assets/basemetals/alt/chests/jungle_temple.json +++ b/src/main/resources/assets/basemetals/alt/chests/jungle_temple.json @@ -1,678 +1,1068 @@ { - "pools": [ - { - "__comment":"25% chance of an uncommon metal tool", - "rolls": 1, - "entries": [ - { - "type": "empty", - "weight": 900 - }, - { - "type": "item", - "name": "minecraft:iron_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:iron_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:bronze_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:steel_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:invar_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:coldiron_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:mithril_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:aquarium_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_crackhammer", - "weight": 3 - } - ] - }, - { - "__comment":"20% chance per roll of uncommon metal ingots", - "rolls": { + "pools": [ + { + "__comment": "25% chance of an uncommon metal tool", + "rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 900 + }, + { + "type": "item", + "name": "minecraft:iron_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "basemetals:iron_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:iron_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_crackhammer" + } + ] + } + ] + }, + { + "__comment": "20% chance per roll of uncommon metal ingots", + "rolls": { + "min": 1, + "max": 2 + }, + "bonus_rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 72 + }, + { + "type": "item", + "name": "minecraft:gold_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ] + }, + { + "type": "item", + "name": "basemetals:silver_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:silver_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:nickel_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:nickel_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:electrum_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:electrum_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 3, + "max": 12 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { "min": 1, - "max": 2 - }, - "bonus_rolls":1, - "entries": [ - { - "type": "empty", - "weight": 72 - }, - { - "type": "item", - "name": "minecraft:gold_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:silver_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:nickel_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:electrum_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 3, - "max": 12 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:invar_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - } - ] + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_ingot" + } + ] } - ] + ] + } + ] } diff --git a/src/main/resources/assets/basemetals/alt/chests/nether_bridge.json b/src/main/resources/assets/basemetals/alt/chests/nether_bridge.json index a470833c..72da6795 100644 --- a/src/main/resources/assets/basemetals/alt/chests/nether_bridge.json +++ b/src/main/resources/assets/basemetals/alt/chests/nether_bridge.json @@ -1,674 +1,1070 @@ { - "pools": [ - { - "__comment":"25% chance of an uncommon metal tool", - "rolls": 1, - "entries": [ - { - "type": "empty", - "weight": 900 - }, - { - "type": "item", - "name": "minecraft:iron_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:iron_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:bronze_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:steel_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:invar_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:coldiron_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:mithril_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:aquarium_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_crackhammer", - "weight": 3 - } - ] - }, - { - "__comment":"25% chance of rare metal ingots", - "rolls": 1, - "entries": [ - { - "type": "empty", - "weight": 300 - }, - { - "type": "item", - "name": "basemetals:coldiron_ingot", - "weight": 40, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:aquarium_ingot", - "weight": 25, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:mithril_ingot", - "weight": 20, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:platinum_ingot", - "weight": 10, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:adamantine_ingot", - "weight": 10, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:starsteel_ingot", - "weight": 5, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - } - ] + "pools": [ + { + "__comment": "25% chance of an uncommon metal tool", + "rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 900 + }, + { + "type": "item", + "name": "minecraft:iron_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "basemetals:iron_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:iron_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_crackhammer" + } + ] + } + ] + }, + { + "__comment": "25% chance of rare metal ingots", + "rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 300 + }, + { + "type": "item", + "name": "basemetals:coldiron_ingot", + "weight": 40, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_ingot", + "weight": 25, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_ingot", + "weight": 20, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:platinum_ingot", + "weight": 10, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:platinum_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:adamantine_ingot", + "weight": 10, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:adamantine_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:starsteel_ingot", + "weight": 5, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:starsteel_ingot" + } + ] } - ] + ] + } + ] } diff --git a/src/main/resources/assets/basemetals/alt/chests/simple_dungeon.json b/src/main/resources/assets/basemetals/alt/chests/simple_dungeon.json index 30481a99..7893487e 100644 --- a/src/main/resources/assets/basemetals/alt/chests/simple_dungeon.json +++ b/src/main/resources/assets/basemetals/alt/chests/simple_dungeon.json @@ -1,678 +1,1068 @@ { - "pools": [ - { - "__comment":"25% chance of an uncommon metal tool", - "rolls": 1, - "entries": [ - { - "type": "empty", - "weight": 900 - }, - { - "type": "item", - "name": "minecraft:iron_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:iron_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:bronze_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:steel_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:invar_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:coldiron_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:mithril_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:aquarium_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_crackhammer", - "weight": 3 - } - ] - }, - { - "__comment":"10% chance per roll of uncommon metal ingots", - "rolls": { + "pools": [ + { + "__comment": "25% chance of an uncommon metal tool", + "rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 900 + }, + { + "type": "item", + "name": "minecraft:iron_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "basemetals:iron_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:iron_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_crackhammer" + } + ] + } + ] + }, + { + "__comment": "10% chance per roll of uncommon metal ingots", + "rolls": { + "min": 1, + "max": 2 + }, + "bonus_rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 162 + }, + { + "type": "item", + "name": "minecraft:gold_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ] + }, + { + "type": "item", + "name": "basemetals:silver_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:silver_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:nickel_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:nickel_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:electrum_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:electrum_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 3, + "max": 12 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { "min": 1, - "max": 2 - }, - "bonus_rolls":1, - "entries": [ - { - "type": "empty", - "weight": 162 - }, - { - "type": "item", - "name": "minecraft:gold_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:silver_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:nickel_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:electrum_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 3, - "max": 12 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:invar_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - } - ] + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_ingot" + } + ] } - ] + ] + } + ] } diff --git a/src/main/resources/assets/basemetals/alt/chests/spawn_bonus_chest.json b/src/main/resources/assets/basemetals/alt/chests/spawn_bonus_chest.json index d28c8f984..fe85ad01 100644 --- a/src/main/resources/assets/basemetals/alt/chests/spawn_bonus_chest.json +++ b/src/main/resources/assets/basemetals/alt/chests/spawn_bonus_chest.json @@ -1,264 +1,506 @@ { - "pools": [ - { - "__comment":"100% chance of one common-metal tool", - "rolls": 1, - "entries": [ - { - "type": "item", - "name": "minecraft:iron_axe", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_boots", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:iron_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:tin_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:copper_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:bronze_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:steel_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_crackhammer", - "weight": 3 - } - ] + "pools": [ + { + "__comment": "100% chance of one common-metal tool", + "rolls": 1, + "entries": [ + { + "type": "item", + "name": "minecraft:iron_axe", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_boots", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_chestplate", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_helmet", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_hoe", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_leggings", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_pickaxe", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_shovel", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_sword", + "weight": 3 + }, + { + "type": "item", + "name": "basemetals:iron_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:iron_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_crackhammer" + } + ] } - ] + ] + } + ] } diff --git a/src/main/resources/assets/basemetals/alt/chests/stronghold_corridor.json b/src/main/resources/assets/basemetals/alt/chests/stronghold_corridor.json index a470833c..72da6795 100644 --- a/src/main/resources/assets/basemetals/alt/chests/stronghold_corridor.json +++ b/src/main/resources/assets/basemetals/alt/chests/stronghold_corridor.json @@ -1,674 +1,1070 @@ { - "pools": [ - { - "__comment":"25% chance of an uncommon metal tool", - "rolls": 1, - "entries": [ - { - "type": "empty", - "weight": 900 - }, - { - "type": "item", - "name": "minecraft:iron_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "minecraft:iron_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:iron_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:bronze_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:steel_axe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_boots", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_chestplate", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_helmet", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_hoe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_leggings", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_pickaxe", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_shovel", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_sword", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_crackhammer", - "weight": 3, - "functions": [ - { - "function": "minecraft:enchant_with_levels", - "levels": 10, - "treasure": true - } - ] - }, - - { - "type": "item", - "name": "basemetals:invar_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:invar_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:coldiron_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:coldiron_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:mithril_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:mithril_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:aquarium_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:aquarium_crackhammer", - "weight": 3 - } - ] - }, - { - "__comment":"25% chance of rare metal ingots", - "rolls": 1, - "entries": [ - { - "type": "empty", - "weight": 300 - }, - { - "type": "item", - "name": "basemetals:coldiron_ingot", - "weight": 40, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:aquarium_ingot", - "weight": 25, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:mithril_ingot", - "weight": 20, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:platinum_ingot", - "weight": 10, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:adamantine_ingot", - "weight": 10, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:starsteel_ingot", - "weight": 5, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - } - ] + "pools": [ + { + "__comment": "25% chance of an uncommon metal tool", + "rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 900 + }, + { + "type": "item", + "name": "minecraft:iron_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "minecraft:iron_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ] + }, + { + "type": "item", + "name": "basemetals:iron_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:iron_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_axe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_boots", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_chestplate", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_helmet", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_hoe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_leggings", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_pickaxe", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_shovel", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_sword", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_crackhammer", + "weight": 3, + "functions": [ + { + "function": "minecraft:enchant_with_levels", + "levels": 10, + "treasure": true + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:coldiron_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_crackhammer" + } + ] + } + ] + }, + { + "__comment": "25% chance of rare metal ingots", + "rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 300 + }, + { + "type": "item", + "name": "basemetals:coldiron_ingot", + "weight": 40, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:coldiron_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:aquarium_ingot", + "weight": 25, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:aquarium_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:mithril_ingot", + "weight": 20, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:mithril_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:platinum_ingot", + "weight": 10, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:platinum_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:adamantine_ingot", + "weight": 10, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:adamantine_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:starsteel_ingot", + "weight": 5, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:starsteel_ingot" + } + ] } - ] + ] + } + ] } diff --git a/src/main/resources/assets/basemetals/alt/chests/stronghold_crossing.json b/src/main/resources/assets/basemetals/alt/chests/stronghold_crossing.json index 554f19b7..22a49820 100644 --- a/src/main/resources/assets/basemetals/alt/chests/stronghold_crossing.json +++ b/src/main/resources/assets/basemetals/alt/chests/stronghold_crossing.json @@ -1,366 +1,638 @@ { - "pools": [ - { - "__comment":"25% chance of a common-metal tool", - "rolls": 1, - "entries": [ - { - "type": "empty", - "weight": 450 - }, - { - "type": "item", - "name": "minecraft:iron_axe", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_boots", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:iron_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:tin_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:copper_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:bronze_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:steel_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_crackhammer", - "weight": 3 - } - ] - }, - { - "__comment":"10% chance per roll of uncommon metal ingots", - "rolls": { + "pools": [ + { + "__comment": "25% chance of a common-metal tool", + "rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 450 + }, + { + "type": "item", + "name": "minecraft:iron_axe", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_boots", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_chestplate", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_helmet", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_hoe", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_leggings", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_pickaxe", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_shovel", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_sword", + "weight": 3 + }, + { + "type": "item", + "name": "basemetals:iron_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:iron_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_crackhammer" + } + ] + } + ] + }, + { + "__comment": "10% chance per roll of uncommon metal ingots", + "rolls": { + "min": 1, + "max": 2 + }, + "bonus_rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 162 + }, + { + "type": "item", + "name": "minecraft:gold_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ] + }, + { + "type": "item", + "name": "basemetals:silver_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:silver_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:nickel_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:nickel_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:electrum_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:electrum_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 3, + "max": 12 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:invar_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { "min": 1, - "max": 2 - }, - "bonus_rolls":1, - "entries": [ - { - "type": "empty", - "weight": 162 - }, - { - "type": "item", - "name": "minecraft:gold_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:silver_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:nickel_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:electrum_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:steel_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 3, - "max": 12 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:invar_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 4 - } - } - ] - } - ] + "max": 4 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:invar_ingot" + } + ] } - ] + ] + } + ] } diff --git a/src/main/resources/assets/basemetals/alt/chests/village_blacksmith.json b/src/main/resources/assets/basemetals/alt/chests/village_blacksmith.json index d4f5bf69..8195c3e0 100644 --- a/src/main/resources/assets/basemetals/alt/chests/village_blacksmith.json +++ b/src/main/resources/assets/basemetals/alt/chests/village_blacksmith.json @@ -1,380 +1,658 @@ { - "pools": [ - { - "__comment":"25% chance of a common-metal tool", - "rolls": 1, - "entries": [ - { - "type": "empty", - "weight": 450 - }, - { - "type": "item", - "name": "minecraft:iron_axe", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_boots", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "minecraft:iron_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:iron_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:tin_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:tin_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:copper_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:copper_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:bronze_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:bronze_crackhammer", - "weight": 3 - }, - - { - "type": "item", - "name": "basemetals:steel_axe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_boots", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_chestplate", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_helmet", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_hoe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_leggings", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_pickaxe", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_shovel", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_sword", - "weight": 3 - }, - { - "type": "item", - "name": "basemetals:steel_crackhammer", - "weight": 3 - } - ] - }, - { - "__comment":"10% chance per roll of common metal ingots", - "rolls": { + "pools": [ + { + "__comment": "25% chance of a common-metal tool", + "rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 450 + }, + { + "type": "item", + "name": "minecraft:iron_axe", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_boots", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_chestplate", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_helmet", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_hoe", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_leggings", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_pickaxe", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_shovel", + "weight": 3 + }, + { + "type": "item", + "name": "minecraft:iron_sword", + "weight": 3 + }, + { + "type": "item", + "name": "basemetals:iron_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:iron_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_crackhammer" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_axe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_axe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_boots", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_boots" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_chestplate", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_chestplate" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_helmet", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_helmet" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_hoe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_hoe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_leggings", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_leggings" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_pickaxe", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_pickaxe" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_shovel", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_shovel" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_sword", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_sword" + } + ] + }, + { + "type": "item", + "name": "basemetals:steel_crackhammer", + "weight": 3, + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:steel_crackhammer" + } + ] + } + ] + }, + { + "__comment": "10% chance per roll of common metal ingots", + "rolls": { + "min": 1, + "max": 4 + }, + "bonus_rolls": 1, + "entries": [ + { + "type": "empty", + "weight": 189 + }, + { + "type": "item", + "name": "minecraft:iron_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ] + }, + { + "type": "item", + "name": "basemetals:tin_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:tin_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:lead_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:lead_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:zinc_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:zinc_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:copper_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:copper_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:brass_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { + "min": 1, + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:brass_ingot" + } + ] + }, + { + "type": "item", + "name": "basemetals:bronze_ingot", + "weight": 3, + "functions": [ + { + "function": "set_count", + "count": { "min": 1, - "max": 4 - }, - "bonus_rolls":1, - "entries": [ - { - "type": "empty", - "weight": 189 - }, - { - "type": "item", - "name": "minecraft:iron_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:tin_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:lead_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:zinc_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:copper_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:brass_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - }, - { - "type": "item", - "name": "basemetals:bronze_ingot", - "weight": 3, - "functions": [ - { - "function": "set_count", - "count": { - "min": 1, - "max": 6 - } - } - ] - } - ] + "max": 6 + } + } + ], + "conditions": [ + { + "condition": "basemetals:content_policy", + "item": "basemetals:bronze_ingot" + } + ] } - ] + ] + } + ] } diff --git a/src/main/resources/assets/basemetals/lang/de_de.lang b/src/main/resources/assets/basemetals/lang/de_de.lang index aa2f4b29..eb6ace7f 100644 --- a/src/main/resources/assets/basemetals/lang/de_de.lang +++ b/src/main/resources/assets/basemetals/lang/de_de.lang @@ -1816,3 +1816,68 @@ modifier.toxic-modifier.name=Giftig modifier.toxic-modifier.desc=§oGIFTIGER RÄCHER!§r\nQuecksilber und seine Ethyl- und Methyl-Salze sind extrem giftig und haben neurodegenerative Effekte.\nSie zu einer Waffe oder einem Werkzeug hinzuzufügen, erlaubt diesen deine Feinde zu blenden und zu vergiften. modifier.lead-plated.name=Bleibeschichtung modifier.lead-plated.desc=§oSafety First§r\nWenn du etwas Plutonium oder Uran herumliegen hast und denkst, dass es gut für eine Waffe geeignet wäre, vergiss nicht etwas Abschirmendes hinzuzufügen.\nEine Beschichtung mit Blei wird die tödliche Verstrahlung davon abhalten, dich zu betreffen, während sie deinen Feinden weiterhin schadet. +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Base-Metals-Konfiguration +config.basemetals.restart_guidance=Neustart erforderlich. Die Erzverteilung wird in OreSpawn konfiguriert. +config.basemetals.category.general=Allgemein +config.basemetals.category.general.tooltip=Allgemeine Base-Metals-Funktionen. Änderungen werden nach einem Neustart von Minecraft wirksam. +config.basemetals.category.metals=Basismetalle +config.basemetals.category.metals.tooltip=Inhalte von Base Metals aktivieren oder deaktivieren. Dies ändert nicht die aktuelle OreSpawn-Welterstellungssitzung. +config.basemetals.category.vanilla=Vanilla-Erweiterungen +config.basemetals.category.vanilla.tooltip=Base-Metals-Erweiterungen für Vanilla-Materialien aktivieren oder deaktivieren. +config.basemetals.category.fluids=Geschmolzene Flüssigkeiten +config.basemetals.category.fluids.tooltip=Die Registrierung geschmolzener Flüssigkeiten aktivieren oder deaktivieren. Änderungen werden nach einem Neustart von Minecraft wirksam. +config.basemetals.category.forced_traits=Erzwungene Eigenschaften +config.basemetals.category.forced_traits.tooltip=Die Registrierung von MMDLib-Eigenschaften für Base-Metals-Materialien erzwingen. +config.basemetals.option.achievements=Erfolge +config.basemetals.option.content_mode=Inhaltsmodus +config.basemetals.option.content_mode.tooltip=High Fantasy, Low Fantasy oder Realismus wählen. Die ausgewählte Richtlinie wird nach einem Neustart von Minecraft wirksam. +config.basemetals.content_mode.high_fantasy=High Fantasy +config.basemetals.content_mode.low_fantasy=Low Fantasy +config.basemetals.content_mode.realism=Realismus +config.basemetals.warning.content_mode.title=Inhaltsmodus von Base Metals ändern? +config.basemetals.warning.content_mode.message=Von %s zu %s wechseln? Rezepte, Handel, Beute und Integrationen ändern sich nach dem Neustart. +config.basemetals.warning.content_mode.realism=Von %s zu %s wechseln? Bestehende OreSpawn-Weltprofile bleiben erhalten; Regeln für Adamant, Kalteisen und Sternenstahl müssen bei Bedarf manuell deaktiviert werden. +config.basemetals.warning.confirm=Speichern und später neu starten +config.basemetals.warning.disable_ores.title=Aktion für OreSpawn-Regeln erforderlich +config.basemetals.warning.disable_ores.message=Vor dem Neustart müssen diese Regeln in OreSpawn deaktiviert werden, da fehlende Ausgabeblöcke sonst den Anbieter ungültig machen: %s +config.basemetals.warning.disable_ores.confirm=Trotzdem speichern +config.basemetals.material.adamantine=Adamant +config.basemetals.material.antimony=Antimon +config.basemetals.material.aquarium=Aquarium +config.basemetals.material.bismuth=Bismut +config.basemetals.material.brass=Messing +config.basemetals.material.bronze=Bronze +config.basemetals.material.coldiron=Kalteisen +config.basemetals.material.copper=Kupfer +config.basemetals.material.cupronickel=Kupfernickel +config.basemetals.material.electrum=Elektrum +config.basemetals.material.invar=Invar +config.basemetals.material.lead=Blei +config.basemetals.material.mercury=Quecksilber +config.basemetals.material.mithril=Mithril +config.basemetals.material.nickel=Nickel +config.basemetals.material.pewter=Hartzinn +config.basemetals.material.platinum=Platin +config.basemetals.material.silver=Silber +config.basemetals.material.starsteel=Sternenstahl +config.basemetals.material.steel=Stahl +config.basemetals.material.tin=Zinn +config.basemetals.material.zinc=Zink +config.basemetals.material.charcoal=Holzkohle +config.basemetals.material.coal=Kohle +config.basemetals.material.diamond=Diamant +config.basemetals.material.emerald=Smaragd +config.basemetals.material.gold=Gold +config.basemetals.material.iron=Eisen +config.basemetals.material.stone=Stein +config.basemetals.material.wood=Holz +config.basemetals.material.ender=Ender +config.basemetals.material.quartz=Quarz +config.basemetals.material.obsidian=Obsidian +config.basemetals.material.lapis=Lapislazuli +config.basemetals.material.prismarine=Prismarin +config.basemetals.material.redstone=Redstone +config.basemetals.content_mode.high_fantasy.description=Alle historischen Inhalte und Beschaffungswege von Base Metals bleiben verfügbar. +config.basemetals.content_mode.low_fantasy.description=Fantasymaterialien bleiben erhalten, aber unplausible Ausrüstungs- und Baurezepte werden ausgeblendet. +config.basemetals.content_mode.realism.description=Die Low-Fantasy-Beschränkungen gelten, und der normale Erwerb mythischer Materialien ist deaktiviert. diff --git a/src/main/resources/assets/basemetals/lang/en_au.lang b/src/main/resources/assets/basemetals/lang/en_au.lang index 3bd261e3..fc22a2cd 100644 --- a/src/main/resources/assets/basemetals/lang/en_au.lang +++ b/src/main/resources/assets/basemetals/lang/en_au.lang @@ -572,3 +572,68 @@ item.basemetals.stone_scythe.name=Stone Sickle item.basemetals.tin_scythe.name=Tin Sickle item.basemetals.wood_scythe.name=Wood Sickle item.basemetals.zinc_scythe.name=Zinc Sickle +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Base Metals Configuration +config.basemetals.restart_guidance=Restart required. Ore distribution is configured in OreSpawn. +config.basemetals.category.general=General +config.basemetals.category.general.tooltip=General Base Metals features. Changes take effect after restarting Minecraft. +config.basemetals.category.metals=Base Metals +config.basemetals.category.metals.tooltip=Enable or disable Base Metals content. This does not change the current OreSpawn world-creation session. +config.basemetals.category.vanilla=Vanilla Bits +config.basemetals.category.vanilla.tooltip=Enable or disable Base Metals additions for vanilla materials. +config.basemetals.category.fluids=Molten Fluids +config.basemetals.category.fluids.tooltip=Enable or disable molten fluid registration. Changes take effect after restarting Minecraft. +config.basemetals.category.forced_traits=Forced Traits +config.basemetals.category.forced_traits.tooltip=Force MMDLib trait registration for Base Metals materials. +config.basemetals.option.achievements=Achievements +config.basemetals.option.content_mode=Content Mode +config.basemetals.option.content_mode.tooltip=Choose High Fantasy, Low Fantasy, or Realism. The selected policy takes effect after restarting Minecraft. +config.basemetals.content_mode.high_fantasy=High Fantasy +config.basemetals.content_mode.low_fantasy=Low Fantasy +config.basemetals.content_mode.realism=Realism +config.basemetals.warning.content_mode.title=Change Base Metals content mode? +config.basemetals.warning.content_mode.message=Change from %s to %s? Recipes, trades, loot and integrations will change after restart. +config.basemetals.warning.content_mode.realism=Change from %s to %s? Existing OreSpawn world profiles are preserved; disable Adamantine, Cold Iron and Starsteel rules manually where required. +config.basemetals.warning.confirm=Save and restart later +config.basemetals.warning.disable_ores.title=OreSpawn rule action required +config.basemetals.warning.disable_ores.message=Before restarting, disable these rules in OreSpawn or their missing output blocks will invalidate the provider: %s +config.basemetals.warning.disable_ores.confirm=Save anyway +config.basemetals.material.adamantine=Adamantine +config.basemetals.material.antimony=Antimony +config.basemetals.material.aquarium=Aquarium +config.basemetals.material.bismuth=Bismuth +config.basemetals.material.brass=Brass +config.basemetals.material.bronze=Bronze +config.basemetals.material.coldiron=Cold Iron +config.basemetals.material.copper=Copper +config.basemetals.material.cupronickel=Cupronickel +config.basemetals.material.electrum=Electrum +config.basemetals.material.invar=Invar +config.basemetals.material.lead=Lead +config.basemetals.material.mercury=Mercury +config.basemetals.material.mithril=Mithril +config.basemetals.material.nickel=Nickel +config.basemetals.material.pewter=Pewter +config.basemetals.material.platinum=Platinum +config.basemetals.material.silver=Silver +config.basemetals.material.starsteel=Starsteel +config.basemetals.material.steel=Steel +config.basemetals.material.tin=Tin +config.basemetals.material.zinc=Zinc +config.basemetals.material.charcoal=Charcoal +config.basemetals.material.coal=Coal +config.basemetals.material.diamond=Diamond +config.basemetals.material.emerald=Emerald +config.basemetals.material.gold=Gold +config.basemetals.material.iron=Iron +config.basemetals.material.stone=Stone +config.basemetals.material.wood=Wood +config.basemetals.material.ender=Ender +config.basemetals.material.quartz=Quartz +config.basemetals.material.obsidian=Obsidian +config.basemetals.material.lapis=Lapis Lazuli +config.basemetals.material.prismarine=Prismarine +config.basemetals.material.redstone=Redstone +config.basemetals.content_mode.high_fantasy.description=All historical Base Metals content and acquisition routes remain available. +config.basemetals.content_mode.low_fantasy.description=Fantasy materials remain, but implausible equipment and construction recipes are hidden. +config.basemetals.content_mode.realism.description=Low Fantasy restrictions apply and normal acquisition of mythical materials is disabled. diff --git a/src/main/resources/assets/basemetals/lang/en_ca.lang b/src/main/resources/assets/basemetals/lang/en_ca.lang index ba52bd74..21142cce 100644 --- a/src/main/resources/assets/basemetals/lang/en_ca.lang +++ b/src/main/resources/assets/basemetals/lang/en_ca.lang @@ -574,3 +574,68 @@ item.basemetals.stone_scythe.name=Stone Sickle item.basemetals.tin_scythe.name=Tin Sickle item.basemetals.wood_scythe.name=Wood Sickle item.basemetals.zinc_scythe.name=Zinc Sickle +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Base Metals Configuration +config.basemetals.restart_guidance=Restart required. Ore distribution is configured in OreSpawn. +config.basemetals.category.general=General +config.basemetals.category.general.tooltip=General Base Metals features. Changes take effect after restarting Minecraft. +config.basemetals.category.metals=Base Metals +config.basemetals.category.metals.tooltip=Enable or disable Base Metals content. This does not change the current OreSpawn world-creation session. +config.basemetals.category.vanilla=Vanilla Bits +config.basemetals.category.vanilla.tooltip=Enable or disable Base Metals additions for vanilla materials. +config.basemetals.category.fluids=Molten Fluids +config.basemetals.category.fluids.tooltip=Enable or disable molten fluid registration. Changes take effect after restarting Minecraft. +config.basemetals.category.forced_traits=Forced Traits +config.basemetals.category.forced_traits.tooltip=Force MMDLib trait registration for Base Metals materials. +config.basemetals.option.achievements=Achievements +config.basemetals.option.content_mode=Content Mode +config.basemetals.option.content_mode.tooltip=Choose High Fantasy, Low Fantasy, or Realism. The selected policy takes effect after restarting Minecraft. +config.basemetals.content_mode.high_fantasy=High Fantasy +config.basemetals.content_mode.low_fantasy=Low Fantasy +config.basemetals.content_mode.realism=Realism +config.basemetals.warning.content_mode.title=Change Base Metals content mode? +config.basemetals.warning.content_mode.message=Change from %s to %s? Recipes, trades, loot and integrations will change after restart. +config.basemetals.warning.content_mode.realism=Change from %s to %s? Existing OreSpawn world profiles are preserved; disable Adamantine, Cold Iron and Starsteel rules manually where required. +config.basemetals.warning.confirm=Save and restart later +config.basemetals.warning.disable_ores.title=OreSpawn rule action required +config.basemetals.warning.disable_ores.message=Before restarting, disable these rules in OreSpawn or their missing output blocks will invalidate the provider: %s +config.basemetals.warning.disable_ores.confirm=Save anyway +config.basemetals.material.adamantine=Adamantine +config.basemetals.material.antimony=Antimony +config.basemetals.material.aquarium=Aquarium +config.basemetals.material.bismuth=Bismuth +config.basemetals.material.brass=Brass +config.basemetals.material.bronze=Bronze +config.basemetals.material.coldiron=Cold Iron +config.basemetals.material.copper=Copper +config.basemetals.material.cupronickel=Cupronickel +config.basemetals.material.electrum=Electrum +config.basemetals.material.invar=Invar +config.basemetals.material.lead=Lead +config.basemetals.material.mercury=Mercury +config.basemetals.material.mithril=Mithril +config.basemetals.material.nickel=Nickel +config.basemetals.material.pewter=Pewter +config.basemetals.material.platinum=Platinum +config.basemetals.material.silver=Silver +config.basemetals.material.starsteel=Starsteel +config.basemetals.material.steel=Steel +config.basemetals.material.tin=Tin +config.basemetals.material.zinc=Zinc +config.basemetals.material.charcoal=Charcoal +config.basemetals.material.coal=Coal +config.basemetals.material.diamond=Diamond +config.basemetals.material.emerald=Emerald +config.basemetals.material.gold=Gold +config.basemetals.material.iron=Iron +config.basemetals.material.stone=Stone +config.basemetals.material.wood=Wood +config.basemetals.material.ender=Ender +config.basemetals.material.quartz=Quartz +config.basemetals.material.obsidian=Obsidian +config.basemetals.material.lapis=Lapis Lazuli +config.basemetals.material.prismarine=Prismarine +config.basemetals.material.redstone=Redstone +config.basemetals.content_mode.high_fantasy.description=All historical Base Metals content and acquisition routes remain available. +config.basemetals.content_mode.low_fantasy.description=Fantasy materials remain, but implausible equipment and construction recipes are hidden. +config.basemetals.content_mode.realism.description=Low Fantasy restrictions apply and normal acquisition of mythical materials is disabled. diff --git a/src/main/resources/assets/basemetals/lang/en_en.lang b/src/main/resources/assets/basemetals/lang/en_en.lang index 29d67a05..fdd53bcc 100644 --- a/src/main/resources/assets/basemetals/lang/en_en.lang +++ b/src/main/resources/assets/basemetals/lang/en_en.lang @@ -573,3 +573,68 @@ item.basemetals.stone_scythe.name=Stone Sickle item.basemetals.tin_scythe.name=Tin Sickle item.basemetals.wood_scythe.name=Wood Sickle item.basemetals.zinc_scythe.name=Zinc Sickle +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Base Metals Configuration +config.basemetals.restart_guidance=Restart required. Ore distribution is configured in OreSpawn. +config.basemetals.category.general=General +config.basemetals.category.general.tooltip=General Base Metals features. Changes take effect after restarting Minecraft. +config.basemetals.category.metals=Base Metals +config.basemetals.category.metals.tooltip=Enable or disable Base Metals content. This does not change the current OreSpawn world-creation session. +config.basemetals.category.vanilla=Vanilla Bits +config.basemetals.category.vanilla.tooltip=Enable or disable Base Metals additions for vanilla materials. +config.basemetals.category.fluids=Molten Fluids +config.basemetals.category.fluids.tooltip=Enable or disable molten fluid registration. Changes take effect after restarting Minecraft. +config.basemetals.category.forced_traits=Forced Traits +config.basemetals.category.forced_traits.tooltip=Force MMDLib trait registration for Base Metals materials. +config.basemetals.option.achievements=Achievements +config.basemetals.option.content_mode=Content Mode +config.basemetals.option.content_mode.tooltip=Choose High Fantasy, Low Fantasy, or Realism. The selected policy takes effect after restarting Minecraft. +config.basemetals.content_mode.high_fantasy=High Fantasy +config.basemetals.content_mode.low_fantasy=Low Fantasy +config.basemetals.content_mode.realism=Realism +config.basemetals.warning.content_mode.title=Change Base Metals content mode? +config.basemetals.warning.content_mode.message=Change from %s to %s? Recipes, trades, loot and integrations will change after restart. +config.basemetals.warning.content_mode.realism=Change from %s to %s? Existing OreSpawn world profiles are preserved; disable Adamantine, Cold Iron and Starsteel rules manually where required. +config.basemetals.warning.confirm=Save and restart later +config.basemetals.warning.disable_ores.title=OreSpawn rule action required +config.basemetals.warning.disable_ores.message=Before restarting, disable these rules in OreSpawn or their missing output blocks will invalidate the provider: %s +config.basemetals.warning.disable_ores.confirm=Save anyway +config.basemetals.material.adamantine=Adamantine +config.basemetals.material.antimony=Antimony +config.basemetals.material.aquarium=Aquarium +config.basemetals.material.bismuth=Bismuth +config.basemetals.material.brass=Brass +config.basemetals.material.bronze=Bronze +config.basemetals.material.coldiron=Cold Iron +config.basemetals.material.copper=Copper +config.basemetals.material.cupronickel=Cupronickel +config.basemetals.material.electrum=Electrum +config.basemetals.material.invar=Invar +config.basemetals.material.lead=Lead +config.basemetals.material.mercury=Mercury +config.basemetals.material.mithril=Mithril +config.basemetals.material.nickel=Nickel +config.basemetals.material.pewter=Pewter +config.basemetals.material.platinum=Platinum +config.basemetals.material.silver=Silver +config.basemetals.material.starsteel=Starsteel +config.basemetals.material.steel=Steel +config.basemetals.material.tin=Tin +config.basemetals.material.zinc=Zinc +config.basemetals.material.charcoal=Charcoal +config.basemetals.material.coal=Coal +config.basemetals.material.diamond=Diamond +config.basemetals.material.emerald=Emerald +config.basemetals.material.gold=Gold +config.basemetals.material.iron=Iron +config.basemetals.material.stone=Stone +config.basemetals.material.wood=Wood +config.basemetals.material.ender=Ender +config.basemetals.material.quartz=Quartz +config.basemetals.material.obsidian=Obsidian +config.basemetals.material.lapis=Lapis Lazuli +config.basemetals.material.prismarine=Prismarine +config.basemetals.material.redstone=Redstone +config.basemetals.content_mode.high_fantasy.description=All historical Base Metals content and acquisition routes remain available. +config.basemetals.content_mode.low_fantasy.description=Fantasy materials remain, but implausible equipment and construction recipes are hidden. +config.basemetals.content_mode.realism.description=Low Fantasy restrictions apply and normal acquisition of mythical materials is disabled. diff --git a/src/main/resources/assets/basemetals/lang/en_gb.lang b/src/main/resources/assets/basemetals/lang/en_gb.lang index cbd43e95..88d79f61 100644 --- a/src/main/resources/assets/basemetals/lang/en_gb.lang +++ b/src/main/resources/assets/basemetals/lang/en_gb.lang @@ -574,3 +574,68 @@ tile.basemetals.stone_anvil.veryDamaged.name=Badly Damaged Stone Anvil tile.basemetals.adamantine_anvil.intact.name=Adamantine Anvil tile.basemetals.adamantine_anvil.slightlyDamaged.name=Slightly Damaged Adamantine Anvil tile.basemetals.adamantine_anvil.veryDamaged.name=Badly Damaged Adamantine Anvil +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Base Metals Configuration +config.basemetals.restart_guidance=Restart required. Ore distribution is configured in OreSpawn. +config.basemetals.category.general=General +config.basemetals.category.general.tooltip=General Base Metals features. Changes take effect after restarting Minecraft. +config.basemetals.category.metals=Base Metals +config.basemetals.category.metals.tooltip=Enable or disable Base Metals content. This does not change the current OreSpawn world-creation session. +config.basemetals.category.vanilla=Vanilla Bits +config.basemetals.category.vanilla.tooltip=Enable or disable Base Metals additions for vanilla materials. +config.basemetals.category.fluids=Molten Fluids +config.basemetals.category.fluids.tooltip=Enable or disable molten fluid registration. Changes take effect after restarting Minecraft. +config.basemetals.category.forced_traits=Forced Traits +config.basemetals.category.forced_traits.tooltip=Force MMDLib trait registration for Base Metals materials. +config.basemetals.option.achievements=Achievements +config.basemetals.option.content_mode=Content Mode +config.basemetals.option.content_mode.tooltip=Choose High Fantasy, Low Fantasy, or Realism. The selected policy takes effect after restarting Minecraft. +config.basemetals.content_mode.high_fantasy=High Fantasy +config.basemetals.content_mode.low_fantasy=Low Fantasy +config.basemetals.content_mode.realism=Realism +config.basemetals.warning.content_mode.title=Change Base Metals content mode? +config.basemetals.warning.content_mode.message=Change from %s to %s? Recipes, trades, loot and integrations will change after restart. +config.basemetals.warning.content_mode.realism=Change from %s to %s? Existing OreSpawn world profiles are preserved; disable Adamantine, Cold Iron and Starsteel rules manually where required. +config.basemetals.warning.confirm=Save and restart later +config.basemetals.warning.disable_ores.title=OreSpawn rule action required +config.basemetals.warning.disable_ores.message=Before restarting, disable these rules in OreSpawn or their missing output blocks will invalidate the provider: %s +config.basemetals.warning.disable_ores.confirm=Save anyway +config.basemetals.material.adamantine=Adamantine +config.basemetals.material.antimony=Antimony +config.basemetals.material.aquarium=Aquarium +config.basemetals.material.bismuth=Bismuth +config.basemetals.material.brass=Brass +config.basemetals.material.bronze=Bronze +config.basemetals.material.coldiron=Cold Iron +config.basemetals.material.copper=Copper +config.basemetals.material.cupronickel=Cupronickel +config.basemetals.material.electrum=Electrum +config.basemetals.material.invar=Invar +config.basemetals.material.lead=Lead +config.basemetals.material.mercury=Mercury +config.basemetals.material.mithril=Mithril +config.basemetals.material.nickel=Nickel +config.basemetals.material.pewter=Pewter +config.basemetals.material.platinum=Platinum +config.basemetals.material.silver=Silver +config.basemetals.material.starsteel=Starsteel +config.basemetals.material.steel=Steel +config.basemetals.material.tin=Tin +config.basemetals.material.zinc=Zinc +config.basemetals.material.charcoal=Charcoal +config.basemetals.material.coal=Coal +config.basemetals.material.diamond=Diamond +config.basemetals.material.emerald=Emerald +config.basemetals.material.gold=Gold +config.basemetals.material.iron=Iron +config.basemetals.material.stone=Stone +config.basemetals.material.wood=Wood +config.basemetals.material.ender=Ender +config.basemetals.material.quartz=Quartz +config.basemetals.material.obsidian=Obsidian +config.basemetals.material.lapis=Lapis Lazuli +config.basemetals.material.prismarine=Prismarine +config.basemetals.material.redstone=Redstone +config.basemetals.content_mode.high_fantasy.description=All historical Base Metals content and acquisition routes remain available. +config.basemetals.content_mode.low_fantasy.description=Fantasy materials remain, but implausible equipment and construction recipes are hidden. +config.basemetals.content_mode.realism.description=Low Fantasy restrictions apply and normal acquisition of mythical materials is disabled. diff --git a/src/main/resources/assets/basemetals/lang/en_pt.lang b/src/main/resources/assets/basemetals/lang/en_pt.lang index 243866fa..8d95b987 100644 --- a/src/main/resources/assets/basemetals/lang/en_pt.lang +++ b/src/main/resources/assets/basemetals/lang/en_pt.lang @@ -530,3 +530,68 @@ item.basemetals.tin_gear.name=Tin Gear item.basemetals.zinc_gear.name=Zinc Gear item.basemetals.gold_crackhammer.name=Golden Crack Hammer +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Base Metals Ship's Settings +config.basemetals.restart_guidance=Restart yer game, matey. Chart ore waters in OreSpawn. +config.basemetals.category.general=General Orders +config.basemetals.category.general.tooltip=General Base Metals riggin'. Changes take hold after ye restart Minecraft. +config.basemetals.category.metals=Base Metals Cargo +config.basemetals.category.metals.tooltip=Load or unload Base Metals cargo. This will not alter the current OreSpawn world-making voyage. +config.basemetals.category.vanilla=Vanilla Booty +config.basemetals.category.vanilla.tooltip=Load or unload Base Metals additions for vanilla materials. +config.basemetals.category.fluids=Molten Cargo +config.basemetals.category.fluids.tooltip=Load or unload molten fluids. Changes take hold after ye restart Minecraft. +config.basemetals.category.forced_traits=Forced Traits +config.basemetals.category.forced_traits.tooltip=Make MMDLib register traits for Base Metals materials, no questions asked. +config.basemetals.option.achievements=Feats +config.basemetals.option.content_mode=Content Course +config.basemetals.option.content_mode.tooltip=Choose High Fantasy, Low Fantasy, or Realism. Yer chosen course takes hold after restarting Minecraft. +config.basemetals.content_mode.high_fantasy=High Fantasy +config.basemetals.content_mode.low_fantasy=Low Fantasy +config.basemetals.content_mode.realism=Realism +config.basemetals.warning.content_mode.title=Change Base Metals' content course? +config.basemetals.warning.content_mode.message=Sail from %s to %s? Recipes, trades, loot, and integrations change after restart. +config.basemetals.warning.content_mode.realism=Sail from %s to %s? Existing OreSpawn world charts stay untouched; disable Unbreakable, Devil-Iron, and Star-Steel rules by hand where needed. +config.basemetals.warning.confirm=Save and restart later +config.basemetals.warning.disable_ores.title=OreSpawn orders required +config.basemetals.warning.disable_ores.message=Before restarting, disable these OreSpawn rules or missing output blocks will scuttle the provider: %s +config.basemetals.warning.disable_ores.confirm=Save anyway +config.basemetals.material.adamantine=Unbreakable +config.basemetals.material.antimony=Antimony +config.basemetals.material.aquarium=Fish-Steel +config.basemetals.material.bismuth=Bismuth +config.basemetals.material.brass=Brass +config.basemetals.material.bronze=Bronze +config.basemetals.material.coldiron=Devil-Iron +config.basemetals.material.copper=Copper +config.basemetals.material.cupronickel=Cupronickel +config.basemetals.material.electrum=Electrum +config.basemetals.material.invar=Invar +config.basemetals.material.lead=Lead +config.basemetals.material.mercury=Mercury +config.basemetals.material.mithril=Ghost Silver +config.basemetals.material.nickel=Nickel +config.basemetals.material.pewter=Pewter +config.basemetals.material.platinum=Platinum +config.basemetals.material.silver=Silver +config.basemetals.material.starsteel=Star-Steel +config.basemetals.material.steel=Steel +config.basemetals.material.tin=Tin +config.basemetals.material.zinc=Zinc +config.basemetals.material.charcoal=Charcoal +config.basemetals.material.coal=Coal +config.basemetals.material.diamond=Diamond +config.basemetals.material.emerald=Emerald +config.basemetals.material.gold=Gold +config.basemetals.material.iron=Iron +config.basemetals.material.stone=Stone +config.basemetals.material.wood=Wood +config.basemetals.material.ender=Ender +config.basemetals.material.quartz=Quartz +config.basemetals.material.obsidian=Obsidian +config.basemetals.material.lapis=Lapis Lazuli +config.basemetals.material.prismarine=Prismarine +config.basemetals.material.redstone=Redstone +config.basemetals.content_mode.high_fantasy.description=All the old Base Metals cargo and ways to claim it remain aboard. +config.basemetals.content_mode.low_fantasy.description=Fantasy materials remain, but daft equipment and building recipes walk the plank. +config.basemetals.content_mode.realism.description=Low Fantasy limits apply, and mythical materials cannot be gained by ordinary means. diff --git a/src/main/resources/assets/basemetals/lang/en_us.lang b/src/main/resources/assets/basemetals/lang/en_us.lang index 174ff831..a36ef194 100644 --- a/src/main/resources/assets/basemetals/lang/en_us.lang +++ b/src/main/resources/assets/basemetals/lang/en_us.lang @@ -1910,3 +1910,68 @@ gas.cleanGasPlatinum=Clean Platinum Slurry gas.cleanGasNickel=Clean Nickel Slurry gas.cleanGasStarsteel=Clean Star-Steel Slurry gas.cleanGasZinc=Clean Zinc Slurry +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Base Metals Configuration +config.basemetals.restart_guidance=Restart required. Ore distribution is configured in OreSpawn. +config.basemetals.category.general=General +config.basemetals.category.general.tooltip=General Base Metals features. Changes take effect after restarting Minecraft. +config.basemetals.category.metals=Base Metals +config.basemetals.category.metals.tooltip=Enable or disable Base Metals content. This does not change the current OreSpawn world-creation session. +config.basemetals.category.vanilla=Vanilla Bits +config.basemetals.category.vanilla.tooltip=Enable or disable Base Metals additions for vanilla materials. +config.basemetals.category.fluids=Molten Fluids +config.basemetals.category.fluids.tooltip=Enable or disable molten fluid registration. Changes take effect after restarting Minecraft. +config.basemetals.category.forced_traits=Forced Traits +config.basemetals.category.forced_traits.tooltip=Force MMDLib trait registration for Base Metals materials. +config.basemetals.option.achievements=Achievements +config.basemetals.option.content_mode=Content Mode +config.basemetals.option.content_mode.tooltip=Choose High Fantasy, Low Fantasy, or Realism. The selected policy takes effect after restarting Minecraft. +config.basemetals.content_mode.high_fantasy=High Fantasy +config.basemetals.content_mode.low_fantasy=Low Fantasy +config.basemetals.content_mode.realism=Realism +config.basemetals.warning.content_mode.title=Change Base Metals content mode? +config.basemetals.warning.content_mode.message=Change from %s to %s? Recipes, trades, loot and integrations will change after restart. +config.basemetals.warning.content_mode.realism=Change from %s to %s? Existing OreSpawn world profiles are preserved; disable Adamantine, Cold Iron and Starsteel rules manually where required. +config.basemetals.warning.confirm=Save and restart later +config.basemetals.warning.disable_ores.title=OreSpawn rule action required +config.basemetals.warning.disable_ores.message=Before restarting, disable these rules in OreSpawn or their missing output blocks will invalidate the provider: %s +config.basemetals.warning.disable_ores.confirm=Save anyway +config.basemetals.material.adamantine=Adamantine +config.basemetals.material.antimony=Antimony +config.basemetals.material.aquarium=Aquarium +config.basemetals.material.bismuth=Bismuth +config.basemetals.material.brass=Brass +config.basemetals.material.bronze=Bronze +config.basemetals.material.coldiron=Cold Iron +config.basemetals.material.copper=Copper +config.basemetals.material.cupronickel=Cupronickel +config.basemetals.material.electrum=Electrum +config.basemetals.material.invar=Invar +config.basemetals.material.lead=Lead +config.basemetals.material.mercury=Mercury +config.basemetals.material.mithril=Mithril +config.basemetals.material.nickel=Nickel +config.basemetals.material.pewter=Pewter +config.basemetals.material.platinum=Platinum +config.basemetals.material.silver=Silver +config.basemetals.material.starsteel=Starsteel +config.basemetals.material.steel=Steel +config.basemetals.material.tin=Tin +config.basemetals.material.zinc=Zinc +config.basemetals.material.charcoal=Charcoal +config.basemetals.material.coal=Coal +config.basemetals.material.diamond=Diamond +config.basemetals.material.emerald=Emerald +config.basemetals.material.gold=Gold +config.basemetals.material.iron=Iron +config.basemetals.material.stone=Stone +config.basemetals.material.wood=Wood +config.basemetals.material.ender=Ender +config.basemetals.material.quartz=Quartz +config.basemetals.material.obsidian=Obsidian +config.basemetals.material.lapis=Lapis Lazuli +config.basemetals.material.prismarine=Prismarine +config.basemetals.material.redstone=Redstone +config.basemetals.content_mode.high_fantasy.description=All historical Base Metals content and acquisition routes remain available. +config.basemetals.content_mode.low_fantasy.description=Fantasy materials remain, but implausible equipment and construction recipes are hidden. +config.basemetals.content_mode.realism.description=Low Fantasy restrictions apply and normal acquisition of mythical materials is disabled. diff --git a/src/main/resources/assets/basemetals/lang/es_es.lang b/src/main/resources/assets/basemetals/lang/es_es.lang index a6ad0a3e..142c01ab 100644 --- a/src/main/resources/assets/basemetals/lang/es_es.lang +++ b/src/main/resources/assets/basemetals/lang/es_es.lang @@ -529,3 +529,68 @@ item.basemetals.starsteel_gear.name=Engranaje de estrellacero item.basemetals.steel_gear.name=Engranaje de acero item.basemetals.tin_gear.name=Engranaje de estaño item.basemetals.zinc_gear.name=Engranaje de zinc +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Configuración de Base Metals +config.basemetals.restart_guidance=Se requiere reiniciar. La distribución de minerales se configura en OreSpawn. +config.basemetals.category.general=General +config.basemetals.category.general.tooltip=Funciones generales de Base Metals. Los cambios se aplican después de reiniciar Minecraft. +config.basemetals.category.metals=Metales básicos +config.basemetals.category.metals.tooltip=Activa o desactiva contenido de Base Metals. Esto no modifica la sesión actual de creación de mundos de OreSpawn. +config.basemetals.category.vanilla=Complementos de Vanilla +config.basemetals.category.vanilla.tooltip=Activa o desactiva las adiciones de Base Metals para materiales de Vanilla. +config.basemetals.category.fluids=Fluidos fundidos +config.basemetals.category.fluids.tooltip=Activa o desactiva el registro de fluidos fundidos. Los cambios se aplican después de reiniciar Minecraft. +config.basemetals.category.forced_traits=Rasgos forzados +config.basemetals.category.forced_traits.tooltip=Fuerza el registro de rasgos de MMDLib para los materiales de Base Metals. +config.basemetals.option.achievements=Logros +config.basemetals.option.content_mode=Modo de contenido +config.basemetals.option.content_mode.tooltip=Elige Alta fantasía, Baja fantasía o Realismo. La política seleccionada se aplica después de reiniciar Minecraft. +config.basemetals.content_mode.high_fantasy=Alta fantasía +config.basemetals.content_mode.low_fantasy=Baja fantasía +config.basemetals.content_mode.realism=Realismo +config.basemetals.warning.content_mode.title=¿Cambiar el modo de contenido de Base Metals? +config.basemetals.warning.content_mode.message=¿Cambiar de %s a %s? Las recetas, los intercambios, el botín y las integraciones cambiarán después de reiniciar. +config.basemetals.warning.content_mode.realism=¿Cambiar de %s a %s? Los perfiles de mundo existentes de OreSpawn se conservarán; desactiva manualmente las reglas de adamantina, glacierro y estrellacero cuando sea necesario. +config.basemetals.warning.confirm=Guardar y reiniciar más tarde +config.basemetals.warning.disable_ores.title=Se requiere una acción en las reglas de OreSpawn +config.basemetals.warning.disable_ores.message=Antes de reiniciar, desactiva estas reglas en OreSpawn o la falta de sus bloques de salida invalidará el proveedor: %s +config.basemetals.warning.disable_ores.confirm=Guardar de todos modos +config.basemetals.material.adamantine=Adamantina +config.basemetals.material.antimony=Antimonio +config.basemetals.material.aquarium=Aquarium +config.basemetals.material.bismuth=Bismuto +config.basemetals.material.brass=Latón +config.basemetals.material.bronze=Bronce +config.basemetals.material.coldiron=Glacierro +config.basemetals.material.copper=Cobre +config.basemetals.material.cupronickel=Cuproníquel +config.basemetals.material.electrum=Electrio +config.basemetals.material.invar=Invar +config.basemetals.material.lead=Plomo +config.basemetals.material.mercury=Mercurio +config.basemetals.material.mithril=Mithril +config.basemetals.material.nickel=Níquel +config.basemetals.material.pewter=Peltre +config.basemetals.material.platinum=Platino +config.basemetals.material.silver=Plata +config.basemetals.material.starsteel=Estrellacero +config.basemetals.material.steel=Acero +config.basemetals.material.tin=Estaño +config.basemetals.material.zinc=Zinc +config.basemetals.material.charcoal=Carbón vegetal +config.basemetals.material.coal=Carbón +config.basemetals.material.diamond=Diamante +config.basemetals.material.emerald=Esmeralda +config.basemetals.material.gold=Oro +config.basemetals.material.iron=Hierro +config.basemetals.material.stone=Piedra +config.basemetals.material.wood=Madera +config.basemetals.material.ender=Ender +config.basemetals.material.quartz=Cuarzo +config.basemetals.material.obsidian=Obsidiana +config.basemetals.material.lapis=Lapislázuli +config.basemetals.material.prismarine=Prismarina +config.basemetals.material.redstone=Redstone +config.basemetals.content_mode.high_fantasy.description=Todo el contenido histórico y las vías de obtención de Base Metals siguen disponibles. +config.basemetals.content_mode.low_fantasy.description=Los materiales fantásticos permanecen, pero se ocultan las recetas de equipo y construcción poco plausibles. +config.basemetals.content_mode.realism.description=Se aplican las restricciones de Baja fantasía y se desactiva la obtención normal de materiales míticos. diff --git a/src/main/resources/assets/basemetals/lang/es_mx.lang b/src/main/resources/assets/basemetals/lang/es_mx.lang index e01fe771..ab9a58d9 100644 --- a/src/main/resources/assets/basemetals/lang/es_mx.lang +++ b/src/main/resources/assets/basemetals/lang/es_mx.lang @@ -530,3 +530,68 @@ item.basemetals.starsteel_gear.name=Engranaje de estrellacero item.basemetals.steel_gear.name=Engranaje de acero item.basemetals.tin_gear.name=Engranaje de estaño item.basemetals.zinc_gear.name=Engranaje de zinc +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Configuración de Base Metals +config.basemetals.restart_guidance=Se requiere reiniciar. La distribución de minerales se configura en OreSpawn. +config.basemetals.category.general=General +config.basemetals.category.general.tooltip=Funciones generales de Base Metals. Los cambios se aplican después de reiniciar Minecraft. +config.basemetals.category.metals=Metales básicos +config.basemetals.category.metals.tooltip=Activa o desactiva contenido de Base Metals. Esto no modifica la sesión actual de creación de mundos de OreSpawn. +config.basemetals.category.vanilla=Complementos de Vanilla +config.basemetals.category.vanilla.tooltip=Activa o desactiva las adiciones de Base Metals para materiales de Vanilla. +config.basemetals.category.fluids=Fluidos fundidos +config.basemetals.category.fluids.tooltip=Activa o desactiva el registro de fluidos fundidos. Los cambios se aplican después de reiniciar Minecraft. +config.basemetals.category.forced_traits=Rasgos forzados +config.basemetals.category.forced_traits.tooltip=Fuerza el registro de rasgos de MMDLib para los materiales de Base Metals. +config.basemetals.option.achievements=Logros +config.basemetals.option.content_mode=Modo de contenido +config.basemetals.option.content_mode.tooltip=Elige Alta fantasía, Baja fantasía o Realismo. La política seleccionada se aplica después de reiniciar Minecraft. +config.basemetals.content_mode.high_fantasy=Alta fantasía +config.basemetals.content_mode.low_fantasy=Baja fantasía +config.basemetals.content_mode.realism=Realismo +config.basemetals.warning.content_mode.title=¿Cambiar el modo de contenido de Base Metals? +config.basemetals.warning.content_mode.message=¿Cambiar de %s a %s? Las recetas, los intercambios, el botín y las integraciones cambiarán después de reiniciar. +config.basemetals.warning.content_mode.realism=¿Cambiar de %s a %s? Los perfiles de mundo existentes de OreSpawn se conservarán; desactiva manualmente las reglas de adamantina, glacierro y estrellacero cuando sea necesario. +config.basemetals.warning.confirm=Guardar y reiniciar más tarde +config.basemetals.warning.disable_ores.title=Se requiere una acción en las reglas de OreSpawn +config.basemetals.warning.disable_ores.message=Antes de reiniciar, desactiva estas reglas en OreSpawn o la falta de sus bloques de salida invalidará el proveedor: %s +config.basemetals.warning.disable_ores.confirm=Guardar de todos modos +config.basemetals.material.adamantine=Adamantina +config.basemetals.material.antimony=Antimonio +config.basemetals.material.aquarium=Aquarium +config.basemetals.material.bismuth=Bismuto +config.basemetals.material.brass=Latón +config.basemetals.material.bronze=Bronce +config.basemetals.material.coldiron=Glacierro +config.basemetals.material.copper=Cobre +config.basemetals.material.cupronickel=Cuproníquel +config.basemetals.material.electrum=Electrio +config.basemetals.material.invar=Invar +config.basemetals.material.lead=Plomo +config.basemetals.material.mercury=Mercurio +config.basemetals.material.mithril=Mithril +config.basemetals.material.nickel=Níquel +config.basemetals.material.pewter=Peltre +config.basemetals.material.platinum=Platino +config.basemetals.material.silver=Plata +config.basemetals.material.starsteel=Estrellacero +config.basemetals.material.steel=Acero +config.basemetals.material.tin=Estaño +config.basemetals.material.zinc=Zinc +config.basemetals.material.charcoal=Carbón vegetal +config.basemetals.material.coal=Carbón +config.basemetals.material.diamond=Diamante +config.basemetals.material.emerald=Esmeralda +config.basemetals.material.gold=Oro +config.basemetals.material.iron=Hierro +config.basemetals.material.stone=Piedra +config.basemetals.material.wood=Madera +config.basemetals.material.ender=Ender +config.basemetals.material.quartz=Cuarzo +config.basemetals.material.obsidian=Obsidiana +config.basemetals.material.lapis=Lapislázuli +config.basemetals.material.prismarine=Prismarina +config.basemetals.material.redstone=Redstone +config.basemetals.content_mode.high_fantasy.description=Todo el contenido histórico y las vías de obtención de Base Metals siguen disponibles. +config.basemetals.content_mode.low_fantasy.description=Los materiales fantásticos permanecen, pero se ocultan las recetas de equipo y construcción poco plausibles. +config.basemetals.content_mode.realism.description=Se aplican las restricciones de Baja fantasía y se desactiva la obtención normal de materiales míticos. diff --git a/src/main/resources/assets/basemetals/lang/fr_ca.lang b/src/main/resources/assets/basemetals/lang/fr_ca.lang index ba2af567..3260fcbd 100644 --- a/src/main/resources/assets/basemetals/lang/fr_ca.lang +++ b/src/main/resources/assets/basemetals/lang/fr_ca.lang @@ -532,3 +532,68 @@ item.basemetals.starsteel_gear.name=Pignon en acier-étoile item.basemetals.steel_gear.name=Pignon en acier item.basemetals.tin_gear.name=Pignon en étain item.basemetals.zinc_gear.name=Pignon de zinc +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Configuration de Base Metals +config.basemetals.restart_guidance=Redémarrage requis. La répartition des minerais se configure dans OreSpawn. +config.basemetals.category.general=Général +config.basemetals.category.general.tooltip=Fonctions générales de Base Metals. Les modifications prennent effet après le redémarrage de Minecraft. +config.basemetals.category.metals=Métaux de base +config.basemetals.category.metals.tooltip=Active ou désactive le contenu de Base Metals. Cela ne modifie pas la session de création de monde OreSpawn en cours. +config.basemetals.category.vanilla=Compléments Vanilla +config.basemetals.category.vanilla.tooltip=Active ou désactive les ajouts de Base Metals pour les matériaux Vanilla. +config.basemetals.category.fluids=Fluides en fusion +config.basemetals.category.fluids.tooltip=Active ou désactive l’enregistrement des fluides en fusion. Les modifications prennent effet après le redémarrage de Minecraft. +config.basemetals.category.forced_traits=Traits forcés +config.basemetals.category.forced_traits.tooltip=Force l’enregistrement des traits MMDLib pour les matériaux de Base Metals. +config.basemetals.option.achievements=Succès +config.basemetals.option.content_mode=Mode de contenu +config.basemetals.option.content_mode.tooltip=Choisissez Fantaisie élevée, Fantaisie modérée ou Réalisme. La politique choisie prend effet après le redémarrage de Minecraft. +config.basemetals.content_mode.high_fantasy=Fantaisie élevée +config.basemetals.content_mode.low_fantasy=Fantaisie modérée +config.basemetals.content_mode.realism=Réalisme +config.basemetals.warning.content_mode.title=Modifier le mode de contenu de Base Metals ? +config.basemetals.warning.content_mode.message=Passer de %s à %s ? Les recettes, échanges, butins et intégrations changeront après le redémarrage. +config.basemetals.warning.content_mode.realism=Passer de %s à %s ? Les profils de monde OreSpawn existants sont conservés ; désactivez manuellement les règles de l’adamantin, du fer-froid et de l’acier stellaire si nécessaire. +config.basemetals.warning.confirm=Enregistrer et redémarrer plus tard +config.basemetals.warning.disable_ores.title=Action requise pour les règles OreSpawn +config.basemetals.warning.disable_ores.message=Avant de redémarrer, désactivez ces règles dans OreSpawn, sinon l’absence de leurs blocs de sortie invalidera le fournisseur : %s +config.basemetals.warning.disable_ores.confirm=Enregistrer quand même +config.basemetals.material.adamantine=Adamantin +config.basemetals.material.antimony=Antimoine +config.basemetals.material.aquarium=Aquarium +config.basemetals.material.bismuth=Bismuth +config.basemetals.material.brass=Laiton +config.basemetals.material.bronze=Bronze +config.basemetals.material.coldiron=Fer-froid +config.basemetals.material.copper=Cuivre +config.basemetals.material.cupronickel=Cupronickel +config.basemetals.material.electrum=Électrum +config.basemetals.material.invar=Invar +config.basemetals.material.lead=Plomb +config.basemetals.material.mercury=Mercure +config.basemetals.material.mithril=Mithril +config.basemetals.material.nickel=Nickel +config.basemetals.material.pewter=Étain allié +config.basemetals.material.platinum=Platine +config.basemetals.material.silver=Argent +config.basemetals.material.starsteel=Acier stellaire +config.basemetals.material.steel=Acier +config.basemetals.material.tin=Étain +config.basemetals.material.zinc=Zinc +config.basemetals.material.charcoal=Charbon de bois +config.basemetals.material.coal=Charbon +config.basemetals.material.diamond=Diamant +config.basemetals.material.emerald=Émeraude +config.basemetals.material.gold=Or +config.basemetals.material.iron=Fer +config.basemetals.material.stone=Pierre +config.basemetals.material.wood=Bois +config.basemetals.material.ender=Ender +config.basemetals.material.quartz=Quartz +config.basemetals.material.obsidian=Obsidienne +config.basemetals.material.lapis=Lapis-lazuli +config.basemetals.material.prismarine=Prismarine +config.basemetals.material.redstone=Redstone +config.basemetals.content_mode.high_fantasy.description=Tout le contenu historique et tous les moyens d’obtention de Base Metals restent disponibles. +config.basemetals.content_mode.low_fantasy.description=Les matériaux fantastiques restent présents, mais les recettes d’équipement et de construction peu plausibles sont masquées. +config.basemetals.content_mode.realism.description=Les restrictions de Fantaisie modérée s’appliquent et l’obtention normale des matériaux mythiques est désactivée. diff --git a/src/main/resources/assets/basemetals/lang/fr_fr.lang b/src/main/resources/assets/basemetals/lang/fr_fr.lang index c5e99b77..efbce775 100644 --- a/src/main/resources/assets/basemetals/lang/fr_fr.lang +++ b/src/main/resources/assets/basemetals/lang/fr_fr.lang @@ -532,3 +532,68 @@ item.basemetals.tin_gear.name=Pignon en étain item.basemetals.zinc_gear.name=Pignon de zinc item.basemetals.gold_crackhammer.name=Massette en or +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Configuration de Base Metals +config.basemetals.restart_guidance=Redémarrage requis. La répartition des minerais se configure dans OreSpawn. +config.basemetals.category.general=Général +config.basemetals.category.general.tooltip=Fonctions générales de Base Metals. Les modifications prennent effet après le redémarrage de Minecraft. +config.basemetals.category.metals=Métaux de base +config.basemetals.category.metals.tooltip=Active ou désactive le contenu de Base Metals. Cela ne modifie pas la session de création de monde OreSpawn en cours. +config.basemetals.category.vanilla=Compléments Vanilla +config.basemetals.category.vanilla.tooltip=Active ou désactive les ajouts de Base Metals pour les matériaux Vanilla. +config.basemetals.category.fluids=Fluides en fusion +config.basemetals.category.fluids.tooltip=Active ou désactive l’enregistrement des fluides en fusion. Les modifications prennent effet après le redémarrage de Minecraft. +config.basemetals.category.forced_traits=Traits forcés +config.basemetals.category.forced_traits.tooltip=Force l’enregistrement des traits MMDLib pour les matériaux de Base Metals. +config.basemetals.option.achievements=Succès +config.basemetals.option.content_mode=Mode de contenu +config.basemetals.option.content_mode.tooltip=Choisissez Fantaisie élevée, Fantaisie modérée ou Réalisme. La politique choisie prend effet après le redémarrage de Minecraft. +config.basemetals.content_mode.high_fantasy=Fantaisie élevée +config.basemetals.content_mode.low_fantasy=Fantaisie modérée +config.basemetals.content_mode.realism=Réalisme +config.basemetals.warning.content_mode.title=Modifier le mode de contenu de Base Metals ? +config.basemetals.warning.content_mode.message=Passer de %s à %s ? Les recettes, échanges, butins et intégrations changeront après le redémarrage. +config.basemetals.warning.content_mode.realism=Passer de %s à %s ? Les profils de monde OreSpawn existants sont conservés ; désactivez manuellement les règles de l’adamantin, du fer-froid et de l’acier stellaire si nécessaire. +config.basemetals.warning.confirm=Enregistrer et redémarrer plus tard +config.basemetals.warning.disable_ores.title=Action requise pour les règles OreSpawn +config.basemetals.warning.disable_ores.message=Avant de redémarrer, désactivez ces règles dans OreSpawn, sinon l’absence de leurs blocs de sortie invalidera le fournisseur : %s +config.basemetals.warning.disable_ores.confirm=Enregistrer quand même +config.basemetals.material.adamantine=Adamantin +config.basemetals.material.antimony=Antimoine +config.basemetals.material.aquarium=Aquarium +config.basemetals.material.bismuth=Bismuth +config.basemetals.material.brass=Laiton +config.basemetals.material.bronze=Bronze +config.basemetals.material.coldiron=Fer-froid +config.basemetals.material.copper=Cuivre +config.basemetals.material.cupronickel=Cupronickel +config.basemetals.material.electrum=Électrum +config.basemetals.material.invar=Invar +config.basemetals.material.lead=Plomb +config.basemetals.material.mercury=Mercure +config.basemetals.material.mithril=Mithril +config.basemetals.material.nickel=Nickel +config.basemetals.material.pewter=Étain allié +config.basemetals.material.platinum=Platine +config.basemetals.material.silver=Argent +config.basemetals.material.starsteel=Acier stellaire +config.basemetals.material.steel=Acier +config.basemetals.material.tin=Étain +config.basemetals.material.zinc=Zinc +config.basemetals.material.charcoal=Charbon de bois +config.basemetals.material.coal=Charbon +config.basemetals.material.diamond=Diamant +config.basemetals.material.emerald=Émeraude +config.basemetals.material.gold=Or +config.basemetals.material.iron=Fer +config.basemetals.material.stone=Pierre +config.basemetals.material.wood=Bois +config.basemetals.material.ender=Ender +config.basemetals.material.quartz=Quartz +config.basemetals.material.obsidian=Obsidienne +config.basemetals.material.lapis=Lapis-lazuli +config.basemetals.material.prismarine=Prismarine +config.basemetals.material.redstone=Redstone +config.basemetals.content_mode.high_fantasy.description=Tout le contenu historique et tous les moyens d’obtention de Base Metals restent disponibles. +config.basemetals.content_mode.low_fantasy.description=Les matériaux fantastiques restent présents, mais les recettes d’équipement et de construction peu plausibles sont masquées. +config.basemetals.content_mode.realism.description=Les restrictions de Fantaisie modérée s’appliquent et l’obtention normale des matériaux mythiques est désactivée. diff --git a/src/main/resources/assets/basemetals/lang/it_it.lang b/src/main/resources/assets/basemetals/lang/it_it.lang index 32b4459c..b8091dd2 100644 --- a/src/main/resources/assets/basemetals/lang/it_it.lang +++ b/src/main/resources/assets/basemetals/lang/it_it.lang @@ -527,3 +527,68 @@ item.basemetals.starsteel_gear.name=Ferro-Stelle Ingranaggio item.basemetals.steel_gear.name=Acciaio Ingranaggio item.basemetals.tin_gear.name=Latta Ingranaggio item.basemetals.zinc_gear.name=Zinco Ingranaggio +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Configurazione di Base Metals +config.basemetals.restart_guidance=Riavvio necessario. La distribuzione dei minerali si configura in OreSpawn. +config.basemetals.category.general=Generale +config.basemetals.category.general.tooltip=Funzioni generali di Base Metals. Le modifiche hanno effetto dopo il riavvio di Minecraft. +config.basemetals.category.metals=Metalli di base +config.basemetals.category.metals.tooltip=Attiva o disattiva i contenuti di Base Metals. Questo non modifica la sessione corrente di creazione del mondo di OreSpawn. +config.basemetals.category.vanilla=Aggiunte Vanilla +config.basemetals.category.vanilla.tooltip=Attiva o disattiva le aggiunte di Base Metals per i materiali Vanilla. +config.basemetals.category.fluids=Fluidi fusi +config.basemetals.category.fluids.tooltip=Attiva o disattiva la registrazione dei fluidi fusi. Le modifiche hanno effetto dopo il riavvio di Minecraft. +config.basemetals.category.forced_traits=Tratti forzati +config.basemetals.category.forced_traits.tooltip=Forza la registrazione dei tratti MMDLib per i materiali di Base Metals. +config.basemetals.option.achievements=Obiettivi +config.basemetals.option.content_mode=Modalità contenuti +config.basemetals.option.content_mode.tooltip=Scegli Alta fantasia, Bassa fantasia o Realismo. La politica selezionata ha effetto dopo il riavvio di Minecraft. +config.basemetals.content_mode.high_fantasy=Alta fantasia +config.basemetals.content_mode.low_fantasy=Bassa fantasia +config.basemetals.content_mode.realism=Realismo +config.basemetals.warning.content_mode.title=Cambiare la modalità contenuti di Base Metals? +config.basemetals.warning.content_mode.message=Passare da %s a %s? Ricette, scambi, bottini e integrazioni cambieranno dopo il riavvio. +config.basemetals.warning.content_mode.realism=Passare da %s a %s? I profili mondo OreSpawn esistenti vengono conservati; disattiva manualmente le regole di adamantio, ferro freddo e acciaio stellare quando necessario. +config.basemetals.warning.confirm=Salva e riavvia più tardi +config.basemetals.warning.disable_ores.title=Azione richiesta per le regole OreSpawn +config.basemetals.warning.disable_ores.message=Prima di riavviare, disattiva queste regole in OreSpawn, altrimenti i blocchi di uscita mancanti invalideranno il fornitore: %s +config.basemetals.warning.disable_ores.confirm=Salva comunque +config.basemetals.material.adamantine=Adamantio +config.basemetals.material.antimony=Antimonio +config.basemetals.material.aquarium=Aquarium +config.basemetals.material.bismuth=Bismuto +config.basemetals.material.brass=Ottone +config.basemetals.material.bronze=Bronzo +config.basemetals.material.coldiron=Ferro freddo +config.basemetals.material.copper=Rame +config.basemetals.material.cupronickel=Cupronichel +config.basemetals.material.electrum=Electrum +config.basemetals.material.invar=Invar +config.basemetals.material.lead=Piombo +config.basemetals.material.mercury=Mercurio +config.basemetals.material.mithril=Mithril +config.basemetals.material.nickel=Nichel +config.basemetals.material.pewter=Peltro +config.basemetals.material.platinum=Platino +config.basemetals.material.silver=Argento +config.basemetals.material.starsteel=Acciaio stellare +config.basemetals.material.steel=Acciaio +config.basemetals.material.tin=Stagno +config.basemetals.material.zinc=Zinco +config.basemetals.material.charcoal=Carbonella +config.basemetals.material.coal=Carbone +config.basemetals.material.diamond=Diamante +config.basemetals.material.emerald=Smeraldo +config.basemetals.material.gold=Oro +config.basemetals.material.iron=Ferro +config.basemetals.material.stone=Pietra +config.basemetals.material.wood=Legno +config.basemetals.material.ender=Ender +config.basemetals.material.quartz=Quarzo +config.basemetals.material.obsidian=Ossidiana +config.basemetals.material.lapis=Lapislazzuli +config.basemetals.material.prismarine=Prismarino +config.basemetals.material.redstone=Redstone +config.basemetals.content_mode.high_fantasy.description=Tutti i contenuti storici e i metodi di ottenimento di Base Metals restano disponibili. +config.basemetals.content_mode.low_fantasy.description=I materiali fantastici restano disponibili, ma le ricette poco plausibili per equipaggiamento e costruzioni vengono nascoste. +config.basemetals.content_mode.realism.description=Si applicano le restrizioni di Bassa fantasia e viene disattivato il normale ottenimento dei materiali mitici. diff --git a/src/main/resources/assets/basemetals/lang/ja_jp.lang b/src/main/resources/assets/basemetals/lang/ja_jp.lang index 4ead682e..2082e999 100644 --- a/src/main/resources/assets/basemetals/lang/ja_jp.lang +++ b/src/main/resources/assets/basemetals/lang/ja_jp.lang @@ -1867,3 +1867,68 @@ gas.cleanGasPlatinum=きれいなプラチナのスラリー gas.cleanGasNickel=きれいなニッケルのスラリー gas.cleanGasStarsteel=きれいなスタースチールのスラリー gas.cleanGasZinc=きれいな亜鉛のスラリー +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Base Metals 設定 +config.basemetals.restart_guidance=再起動が必要です。鉱石の分布は OreSpawn で設定します。 +config.basemetals.category.general=一般 +config.basemetals.category.general.tooltip=Base Metals の一般機能です。変更は Minecraft の再起動後に有効になります。 +config.basemetals.category.metals=Base Metals +config.basemetals.category.metals.tooltip=Base Metals のコンテンツを有効または無効にします。現在の OreSpawn ワールド作成セッションには影響しません。 +config.basemetals.category.vanilla=バニラ追加要素 +config.basemetals.category.vanilla.tooltip=バニラ素材向けの Base Metals 追加要素を有効または無効にします。 +config.basemetals.category.fluids=溶融流体 +config.basemetals.category.fluids.tooltip=溶融流体の登録を有効または無効にします。変更は Minecraft の再起動後に有効になります。 +config.basemetals.category.forced_traits=強制特性 +config.basemetals.category.forced_traits.tooltip=Base Metals 素材の MMDLib 特性登録を強制します。 +config.basemetals.option.achievements=実績 +config.basemetals.option.content_mode=コンテンツモード +config.basemetals.option.content_mode.tooltip=ハイファンタジー、ローファンタジー、リアリズムから選択します。選択した方針は Minecraft の再起動後に有効になります。 +config.basemetals.content_mode.high_fantasy=ハイファンタジー +config.basemetals.content_mode.low_fantasy=ローファンタジー +config.basemetals.content_mode.realism=リアリズム +config.basemetals.warning.content_mode.title=Base Metals のコンテンツモードを変更しますか? +config.basemetals.warning.content_mode.message=%s から %s に変更しますか?再起動後にレシピ、取引、戦利品、連携内容が変更されます。 +config.basemetals.warning.content_mode.realism=%s から %s に変更しますか?既存の OreSpawn ワールドプロファイルは保持されます。必要に応じてアダマント、コールドアイアン、スタースチールのルールを手動で無効にしてください。 +config.basemetals.warning.confirm=保存して後で再起動 +config.basemetals.warning.disable_ores.title=OreSpawn ルールの操作が必要です +config.basemetals.warning.disable_ores.message=再起動前に OreSpawn で次のルールを無効にしてください。出力ブロックが存在しないとプロバイダーが無効になります: %s +config.basemetals.warning.disable_ores.confirm=そのまま保存 +config.basemetals.material.adamantine=アダマント +config.basemetals.material.antimony=アンチモン +config.basemetals.material.aquarium=アクアリウム +config.basemetals.material.bismuth=ビスマス +config.basemetals.material.brass=黄銅 +config.basemetals.material.bronze=青銅 +config.basemetals.material.coldiron=コールドアイアン +config.basemetals.material.copper=銅 +config.basemetals.material.cupronickel=白銅 +config.basemetals.material.electrum=エレクトラム +config.basemetals.material.invar=インバー +config.basemetals.material.lead=鉛 +config.basemetals.material.mercury=水銀 +config.basemetals.material.mithril=ミスリル +config.basemetals.material.nickel=ニッケル +config.basemetals.material.pewter=ピューター +config.basemetals.material.platinum=プラチナ +config.basemetals.material.silver=銀 +config.basemetals.material.starsteel=スタースチール +config.basemetals.material.steel=鋼鉄 +config.basemetals.material.tin=錫 +config.basemetals.material.zinc=亜鉛 +config.basemetals.material.charcoal=木炭 +config.basemetals.material.coal=石炭 +config.basemetals.material.diamond=ダイヤモンド +config.basemetals.material.emerald=エメラルド +config.basemetals.material.gold=金 +config.basemetals.material.iron=鉄 +config.basemetals.material.stone=石 +config.basemetals.material.wood=木材 +config.basemetals.material.ender=エンダー +config.basemetals.material.quartz=クォーツ +config.basemetals.material.obsidian=黒曜石 +config.basemetals.material.lapis=ラピスラズリ +config.basemetals.material.prismarine=プリズマリン +config.basemetals.material.redstone=レッドストーン +config.basemetals.content_mode.high_fantasy.description=従来の Base Metals コンテンツと入手経路をすべて利用できます。 +config.basemetals.content_mode.low_fantasy.description=ファンタジー素材は残りますが、不自然な装備や建築レシピは非表示になります。 +config.basemetals.content_mode.realism.description=ローファンタジーの制限に加え、神話素材の通常の入手が無効になります。 diff --git a/src/main/resources/assets/basemetals/lang/nl_nl.lang b/src/main/resources/assets/basemetals/lang/nl_nl.lang index ec306dbf..6891ace5 100644 --- a/src/main/resources/assets/basemetals/lang/nl_nl.lang +++ b/src/main/resources/assets/basemetals/lang/nl_nl.lang @@ -530,3 +530,68 @@ item.basemetals.starsteel_gear.name=Star-Steel Gear item.basemetals.steel_gear.name=Steel Gear item.basemetals.tin_gear.name=Tin Gear item.basemetals.zinc_gear.name=Zinc Gear +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Base Metals-configuratie +config.basemetals.restart_guidance=Opnieuw opstarten vereist. De ertsverdeling wordt in OreSpawn ingesteld. +config.basemetals.category.general=Algemeen +config.basemetals.category.general.tooltip=Algemene functies van Base Metals. Wijzigingen worden actief nadat Minecraft opnieuw is gestart. +config.basemetals.category.metals=Basismetalen +config.basemetals.category.metals.tooltip=Schakel Base Metals-inhoud in of uit. Dit wijzigt de huidige OreSpawn-sessie voor het maken van een wereld niet. +config.basemetals.category.vanilla=Vanilla-uitbreidingen +config.basemetals.category.vanilla.tooltip=Schakel Base Metals-uitbreidingen voor vanilla-materialen in of uit. +config.basemetals.category.fluids=Gesmolten vloeistoffen +config.basemetals.category.fluids.tooltip=Schakel registratie van gesmolten vloeistoffen in of uit. Wijzigingen worden actief nadat Minecraft opnieuw is gestart. +config.basemetals.category.forced_traits=Geforceerde eigenschappen +config.basemetals.category.forced_traits.tooltip=Forceer registratie van MMDLib-eigenschappen voor Base Metals-materialen. +config.basemetals.option.achievements=Prestaties +config.basemetals.option.content_mode=Inhoudsmodus +config.basemetals.option.content_mode.tooltip=Kies Hoge fantasie, Lage fantasie of Realisme. Het gekozen beleid wordt actief nadat Minecraft opnieuw is gestart. +config.basemetals.content_mode.high_fantasy=Hoge fantasie +config.basemetals.content_mode.low_fantasy=Lage fantasie +config.basemetals.content_mode.realism=Realisme +config.basemetals.warning.content_mode.title=De inhoudsmodus van Base Metals wijzigen? +config.basemetals.warning.content_mode.message=Wijzigen van %s naar %s? Recepten, handel, buit en integraties veranderen na het opnieuw opstarten. +config.basemetals.warning.content_mode.realism=Wijzigen van %s naar %s? Bestaande OreSpawn-wereldprofielen blijven behouden; schakel waar nodig de regels voor adamant, koudijzer en sterrenstaal handmatig uit. +config.basemetals.warning.confirm=Opslaan en later opnieuw opstarten +config.basemetals.warning.disable_ores.title=Actie voor OreSpawn-regels vereist +config.basemetals.warning.disable_ores.message=Schakel vóór het opnieuw opstarten deze regels in OreSpawn uit, anders maken ontbrekende uitvoerblokken de provider ongeldig: %s +config.basemetals.warning.disable_ores.confirm=Toch opslaan +config.basemetals.material.adamantine=Adamant +config.basemetals.material.antimony=Antimoon +config.basemetals.material.aquarium=Aquarium +config.basemetals.material.bismuth=Bismut +config.basemetals.material.brass=Messing +config.basemetals.material.bronze=Brons +config.basemetals.material.coldiron=Koudijzer +config.basemetals.material.copper=Koper +config.basemetals.material.cupronickel=Kopernikkel +config.basemetals.material.electrum=Electrum +config.basemetals.material.invar=Invar +config.basemetals.material.lead=Lood +config.basemetals.material.mercury=Kwik +config.basemetals.material.mithril=Mithril +config.basemetals.material.nickel=Nikkel +config.basemetals.material.pewter=Tinnen legering +config.basemetals.material.platinum=Platina +config.basemetals.material.silver=Zilver +config.basemetals.material.starsteel=Sterrenstaal +config.basemetals.material.steel=Staal +config.basemetals.material.tin=Tin +config.basemetals.material.zinc=Zink +config.basemetals.material.charcoal=Houtskool +config.basemetals.material.coal=Steenkool +config.basemetals.material.diamond=Diamant +config.basemetals.material.emerald=Smaragd +config.basemetals.material.gold=Goud +config.basemetals.material.iron=IJzer +config.basemetals.material.stone=Steen +config.basemetals.material.wood=Hout +config.basemetals.material.ender=Ender +config.basemetals.material.quartz=Kwarts +config.basemetals.material.obsidian=Obsidiaan +config.basemetals.material.lapis=Lapis lazuli +config.basemetals.material.prismarine=Prismarien +config.basemetals.material.redstone=Redstone +config.basemetals.content_mode.high_fantasy.description=Alle historische Base Metals-inhoud en verkrijgingsroutes blijven beschikbaar. +config.basemetals.content_mode.low_fantasy.description=Fantasiematerialen blijven bestaan, maar onwaarschijnlijke uitrustings- en bouwrecepten worden verborgen. +config.basemetals.content_mode.realism.description=De beperkingen van Lage fantasie gelden en normale verkrijging van mythische materialen is uitgeschakeld. diff --git a/src/main/resources/assets/basemetals/lang/pt_br.lang b/src/main/resources/assets/basemetals/lang/pt_br.lang index 516abac7..e296e15e 100644 --- a/src/main/resources/assets/basemetals/lang/pt_br.lang +++ b/src/main/resources/assets/basemetals/lang/pt_br.lang @@ -530,3 +530,68 @@ item.basemetals.starsteel_gear.name=Roda Dentada de Ferro-Estrela item.basemetals.steel_gear.name=Roda Dentada de Aço item.basemetals.tin_gear.name=Roda Dentada de Estanho item.basemetals.zinc_gear.name=Roda Dentada de Zinco +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Configuração do Base Metals +config.basemetals.restart_guidance=É necessário reiniciar. A distribuição de minérios é configurada no OreSpawn. +config.basemetals.category.general=Geral +config.basemetals.category.general.tooltip=Recursos gerais do Base Metals. As alterações entram em vigor após reiniciar o Minecraft. +config.basemetals.category.metals=Metais básicos +config.basemetals.category.metals.tooltip=Ative ou desative o conteúdo do Base Metals. Isso não altera a sessão atual de criação de mundo do OreSpawn. +config.basemetals.category.vanilla=Adições Vanilla +config.basemetals.category.vanilla.tooltip=Ative ou desative as adições do Base Metals para materiais Vanilla. +config.basemetals.category.fluids=Fluidos fundidos +config.basemetals.category.fluids.tooltip=Ative ou desative o registro de fluidos fundidos. As alterações entram em vigor após reiniciar o Minecraft. +config.basemetals.category.forced_traits=Características forçadas +config.basemetals.category.forced_traits.tooltip=Force o registro de características do MMDLib para materiais do Base Metals. +config.basemetals.option.achievements=Conquistas +config.basemetals.option.content_mode=Modo de conteúdo +config.basemetals.option.content_mode.tooltip=Escolha Alta fantasia, Baixa fantasia ou Realismo. A política selecionada entra em vigor após reiniciar o Minecraft. +config.basemetals.content_mode.high_fantasy=Alta fantasia +config.basemetals.content_mode.low_fantasy=Baixa fantasia +config.basemetals.content_mode.realism=Realismo +config.basemetals.warning.content_mode.title=Alterar o modo de conteúdo do Base Metals? +config.basemetals.warning.content_mode.message=Alterar de %s para %s? Receitas, trocas, saques e integrações mudarão após reiniciar. +config.basemetals.warning.content_mode.realism=Alterar de %s para %s? Os perfis de mundo existentes do OreSpawn serão preservados; desative manualmente as regras de magnetita, ferro-frio e ferro-estrela quando necessário. +config.basemetals.warning.confirm=Salvar e reiniciar mais tarde +config.basemetals.warning.disable_ores.title=É necessária uma ação nas regras do OreSpawn +config.basemetals.warning.disable_ores.message=Antes de reiniciar, desative estas regras no OreSpawn; caso contrário, a ausência dos blocos de saída invalidará o provedor: %s +config.basemetals.warning.disable_ores.confirm=Salvar mesmo assim +config.basemetals.material.adamantine=Magnetita +config.basemetals.material.antimony=Antimônio +config.basemetals.material.aquarium=Aquarium +config.basemetals.material.bismuth=Bismuto +config.basemetals.material.brass=Latão +config.basemetals.material.bronze=Bronze +config.basemetals.material.coldiron=Ferro-frio +config.basemetals.material.copper=Cobre +config.basemetals.material.cupronickel=Cuproníquel +config.basemetals.material.electrum=Electrum +config.basemetals.material.invar=Invar +config.basemetals.material.lead=Chumbo +config.basemetals.material.mercury=Mercúrio +config.basemetals.material.mithril=Mithril +config.basemetals.material.nickel=Níquel +config.basemetals.material.pewter=Peltre +config.basemetals.material.platinum=Platina +config.basemetals.material.silver=Prata +config.basemetals.material.starsteel=Ferro-estrela +config.basemetals.material.steel=Aço +config.basemetals.material.tin=Estanho +config.basemetals.material.zinc=Zinco +config.basemetals.material.charcoal=Carvão vegetal +config.basemetals.material.coal=Carvão +config.basemetals.material.diamond=Diamante +config.basemetals.material.emerald=Esmeralda +config.basemetals.material.gold=Ouro +config.basemetals.material.iron=Ferro +config.basemetals.material.stone=Pedra +config.basemetals.material.wood=Madeira +config.basemetals.material.ender=Ender +config.basemetals.material.quartz=Quartzo +config.basemetals.material.obsidian=Obsidiana +config.basemetals.material.lapis=Lápis-lazúli +config.basemetals.material.prismarine=Prismarinho +config.basemetals.material.redstone=Redstone +config.basemetals.content_mode.high_fantasy.description=Todo o conteúdo histórico e as formas de obtenção do Base Metals permanecem disponíveis. +config.basemetals.content_mode.low_fantasy.description=Os materiais fantásticos permanecem, mas receitas pouco plausíveis de equipamentos e construções ficam ocultas. +config.basemetals.content_mode.realism.description=As restrições de Baixa fantasia são aplicadas e a obtenção normal de materiais míticos é desativada. diff --git a/src/main/resources/assets/basemetals/lang/ru_ru.lang b/src/main/resources/assets/basemetals/lang/ru_ru.lang index 4764bc30..ca741b9c 100644 --- a/src/main/resources/assets/basemetals/lang/ru_ru.lang +++ b/src/main/resources/assets/basemetals/lang/ru_ru.lang @@ -1844,3 +1844,68 @@ modifier.toxic-modifier.desc=§oТОКСИЧНЫЙ МСТИТЕЛЬ!§r\nРту modifier.lead-plated.name=Свинцовая пластина modifier.lead-plated.desc=§oБезопастность Прежде Всего!§r\nЕсли рядом с вами есть плутоний или уран, я думаю это можно использовать как оружие, не забудьте экранировать излучение.\nХорошая свинцовая пластина может спасти Вас от смертельного излучения, пока Ваших врагов будетубивать радиация. +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Настройки Base Metals +config.basemetals.restart_guidance=Требуется перезапуск. Распределение руд настраивается в OreSpawn. +config.basemetals.category.general=Общие +config.basemetals.category.general.tooltip=Общие функции Base Metals. Изменения вступят в силу после перезапуска Minecraft. +config.basemetals.category.metals=Базовые металлы +config.basemetals.category.metals.tooltip=Включение или отключение содержимого Base Metals. Это не изменяет текущий сеанс создания мира OreSpawn. +config.basemetals.category.vanilla=Дополнения Vanilla +config.basemetals.category.vanilla.tooltip=Включение или отключение дополнений Base Metals для материалов Vanilla. +config.basemetals.category.fluids=Расплавленные жидкости +config.basemetals.category.fluids.tooltip=Включение или отключение регистрации расплавленных жидкостей. Изменения вступят в силу после перезапуска Minecraft. +config.basemetals.category.forced_traits=Принудительные свойства +config.basemetals.category.forced_traits.tooltip=Принудительно регистрировать свойства MMDLib для материалов Base Metals. +config.basemetals.option.achievements=Достижения +config.basemetals.option.content_mode=Режим содержимого +config.basemetals.option.content_mode.tooltip=Выберите «Высокое фэнтези», «Низкое фэнтези» или «Реализм». Выбранная политика вступит в силу после перезапуска Minecraft. +config.basemetals.content_mode.high_fantasy=Высокое фэнтези +config.basemetals.content_mode.low_fantasy=Низкое фэнтези +config.basemetals.content_mode.realism=Реализм +config.basemetals.warning.content_mode.title=Изменить режим содержимого Base Metals? +config.basemetals.warning.content_mode.message=Переключиться с %s на %s? Рецепты, торговля, добыча и интеграции изменятся после перезапуска. +config.basemetals.warning.content_mode.realism=Переключиться с %s на %s? Существующие профили миров OreSpawn сохранятся; при необходимости вручную отключите правила адамантина, хладожелеза и звёздной стали. +config.basemetals.warning.confirm=Сохранить и перезапустить позже +config.basemetals.warning.disable_ores.title=Требуется действие с правилами OreSpawn +config.basemetals.warning.disable_ores.message=Перед перезапуском отключите эти правила в OreSpawn, иначе отсутствие выходных блоков сделает поставщика недействительным: %s +config.basemetals.warning.disable_ores.confirm=Всё равно сохранить +config.basemetals.material.adamantine=Адамантин +config.basemetals.material.antimony=Сурьма +config.basemetals.material.aquarium=Аквариум +config.basemetals.material.bismuth=Висмут +config.basemetals.material.brass=Латунь +config.basemetals.material.bronze=Бронза +config.basemetals.material.coldiron=Хладожелезо +config.basemetals.material.copper=Медь +config.basemetals.material.cupronickel=Мельхиор +config.basemetals.material.electrum=Электрум +config.basemetals.material.invar=Инвар +config.basemetals.material.lead=Свинец +config.basemetals.material.mercury=Ртуть +config.basemetals.material.mithril=Мифрил +config.basemetals.material.nickel=Никель +config.basemetals.material.pewter=Пьютер +config.basemetals.material.platinum=Платина +config.basemetals.material.silver=Серебро +config.basemetals.material.starsteel=Звёздная сталь +config.basemetals.material.steel=Сталь +config.basemetals.material.tin=Олово +config.basemetals.material.zinc=Цинк +config.basemetals.material.charcoal=Древесный уголь +config.basemetals.material.coal=Уголь +config.basemetals.material.diamond=Алмаз +config.basemetals.material.emerald=Изумруд +config.basemetals.material.gold=Золото +config.basemetals.material.iron=Железо +config.basemetals.material.stone=Камень +config.basemetals.material.wood=Дерево +config.basemetals.material.ender=Эндер +config.basemetals.material.quartz=Кварц +config.basemetals.material.obsidian=Обсидиан +config.basemetals.material.lapis=Лазурит +config.basemetals.material.prismarine=Призмарин +config.basemetals.material.redstone=Редстоун +config.basemetals.content_mode.high_fantasy.description=Всё историческое содержимое Base Metals и способы его получения остаются доступными. +config.basemetals.content_mode.low_fantasy.description=Фэнтезийные материалы остаются, но неправдоподобные рецепты снаряжения и строительства скрываются. +config.basemetals.content_mode.realism.description=Применяются ограничения Низкого фэнтези, а обычное получение мифических материалов отключается. diff --git a/src/main/resources/assets/basemetals/lang/zh_cn.lang b/src/main/resources/assets/basemetals/lang/zh_cn.lang index 5d2671bf..7c07e362 100644 --- a/src/main/resources/assets/basemetals/lang/zh_cn.lang +++ b/src/main/resources/assets/basemetals/lang/zh_cn.lang @@ -1810,3 +1810,68 @@ modifier.brittle.name=易碎 modifier.heavy.name=沉重 modifier.reactive.name=活泼 modifier.radioactive.name=放射 +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Base Metals 配置 +config.basemetals.restart_guidance=需要重启。矿石分布请在 OreSpawn 中配置。 +config.basemetals.category.general=常规 +config.basemetals.category.general.tooltip=Base Metals 的常规功能。更改将在重启 Minecraft 后生效。 +config.basemetals.category.metals=基础金属 +config.basemetals.category.metals.tooltip=启用或禁用 Base Metals 内容。此操作不会更改当前 OreSpawn 世界创建会话。 +config.basemetals.category.vanilla=原版扩展 +config.basemetals.category.vanilla.tooltip=启用或禁用 Base Metals 为原版材料添加的内容。 +config.basemetals.category.fluids=熔融流体 +config.basemetals.category.fluids.tooltip=启用或禁用熔融流体注册。更改将在重启 Minecraft 后生效。 +config.basemetals.category.forced_traits=强制特性 +config.basemetals.category.forced_traits.tooltip=强制为 Base Metals 材料注册 MMDLib 特性。 +config.basemetals.option.achievements=成就 +config.basemetals.option.content_mode=内容模式 +config.basemetals.option.content_mode.tooltip=选择高幻想、低幻想或写实模式。所选规则将在重启 Minecraft 后生效。 +config.basemetals.content_mode.high_fantasy=高幻想 +config.basemetals.content_mode.low_fantasy=低幻想 +config.basemetals.content_mode.realism=写实 +config.basemetals.warning.content_mode.title=更改 Base Metals 内容模式? +config.basemetals.warning.content_mode.message=从 %s 更改为 %s?重启后,配方、交易、战利品和模组联动将发生变化。 +config.basemetals.warning.content_mode.realism=从 %s 更改为 %s?现有 OreSpawn 世界配置将保留;必要时请手动禁用艾德曼金属、寒铁和星钢规则。 +config.basemetals.warning.confirm=保存并稍后重启 +config.basemetals.warning.disable_ores.title=需要处理 OreSpawn 规则 +config.basemetals.warning.disable_ores.message=重启前请在 OreSpawn 中禁用以下规则,否则缺失输出方块会使提供程序无效:%s +config.basemetals.warning.disable_ores.confirm=仍然保存 +config.basemetals.material.adamantine=艾德曼金属 +config.basemetals.material.antimony=锑 +config.basemetals.material.aquarium=海洋合金 +config.basemetals.material.bismuth=铋 +config.basemetals.material.brass=黄铜 +config.basemetals.material.bronze=青铜 +config.basemetals.material.coldiron=寒铁 +config.basemetals.material.copper=铜 +config.basemetals.material.cupronickel=白铜 +config.basemetals.material.electrum=琥珀金 +config.basemetals.material.invar=因瓦合金 +config.basemetals.material.lead=铅 +config.basemetals.material.mercury=汞 +config.basemetals.material.mithril=秘银 +config.basemetals.material.nickel=镍 +config.basemetals.material.pewter=白镴 +config.basemetals.material.platinum=铂 +config.basemetals.material.silver=银 +config.basemetals.material.starsteel=星钢 +config.basemetals.material.steel=钢 +config.basemetals.material.tin=锡 +config.basemetals.material.zinc=锌 +config.basemetals.material.charcoal=木炭 +config.basemetals.material.coal=煤炭 +config.basemetals.material.diamond=钻石 +config.basemetals.material.emerald=绿宝石 +config.basemetals.material.gold=金 +config.basemetals.material.iron=铁 +config.basemetals.material.stone=石头 +config.basemetals.material.wood=木材 +config.basemetals.material.ender=末影 +config.basemetals.material.quartz=石英 +config.basemetals.material.obsidian=黑曜石 +config.basemetals.material.lapis=青金石 +config.basemetals.material.prismarine=海晶石 +config.basemetals.material.redstone=红石 +config.basemetals.content_mode.high_fantasy.description=保留所有历史 Base Metals 内容和获取途径。 +config.basemetals.content_mode.low_fantasy.description=保留幻想材料,但隐藏不合理的装备和建筑配方。 +config.basemetals.content_mode.realism.description=应用低幻想限制,并禁用神话材料的常规获取途径。 diff --git a/src/main/resources/assets/basemetals/lang/zh_tw.lang b/src/main/resources/assets/basemetals/lang/zh_tw.lang index b854187d..1d3bb910 100644 --- a/src/main/resources/assets/basemetals/lang/zh_tw.lang +++ b/src/main/resources/assets/basemetals/lang/zh_tw.lang @@ -1884,3 +1884,68 @@ gas.cleanGasPlatinum=純淨的白金漿 gas.cleanGasNickel=純淨的鎳漿 gas.cleanGasStarsteel=純淨的星鋼漿 gas.cleanGasZinc=純淨的鋅漿 +# Base Metals configuration screen (OreSpawn 4.1) +config.basemetals.title=Base Metals 設定 +config.basemetals.restart_guidance=需要重新啟動。礦石分布請在 OreSpawn 中設定。 +config.basemetals.category.general=一般 +config.basemetals.category.general.tooltip=Base Metals 的一般功能。變更會在重新啟動 Minecraft 後生效。 +config.basemetals.category.metals=基礎金屬 +config.basemetals.category.metals.tooltip=啟用或停用 Base Metals 內容。此操作不會變更目前的 OreSpawn 世界建立工作階段。 +config.basemetals.category.vanilla=原版擴充 +config.basemetals.category.vanilla.tooltip=啟用或停用 Base Metals 為原版材料新增的內容。 +config.basemetals.category.fluids=熔融流體 +config.basemetals.category.fluids.tooltip=啟用或停用熔融流體註冊。變更會在重新啟動 Minecraft 後生效。 +config.basemetals.category.forced_traits=強制特性 +config.basemetals.category.forced_traits.tooltip=強制為 Base Metals 材料註冊 MMDLib 特性。 +config.basemetals.option.achievements=成就 +config.basemetals.option.content_mode=內容模式 +config.basemetals.option.content_mode.tooltip=選擇高幻想、低幻想或寫實模式。所選規則會在重新啟動 Minecraft 後生效。 +config.basemetals.content_mode.high_fantasy=高幻想 +config.basemetals.content_mode.low_fantasy=低幻想 +config.basemetals.content_mode.realism=寫實 +config.basemetals.warning.content_mode.title=變更 Base Metals 內容模式? +config.basemetals.warning.content_mode.message=從 %s 變更為 %s?重新啟動後,配方、交易、戰利品與模組整合會隨之變更。 +config.basemetals.warning.content_mode.realism=從 %s 變更為 %s?現有 OreSpawn 世界設定檔會保留;必要時請手動停用精金、寒鐵與星鋼規則。 +config.basemetals.warning.confirm=儲存並稍後重新啟動 +config.basemetals.warning.disable_ores.title=需要處理 OreSpawn 規則 +config.basemetals.warning.disable_ores.message=重新啟動前請在 OreSpawn 中停用以下規則,否則缺少輸出方塊會使提供者失效:%s +config.basemetals.warning.disable_ores.confirm=仍要儲存 +config.basemetals.material.adamantine=精金 +config.basemetals.material.antimony=銻 +config.basemetals.material.aquarium=海洋合金 +config.basemetals.material.bismuth=鉍 +config.basemetals.material.brass=黃銅 +config.basemetals.material.bronze=青銅 +config.basemetals.material.coldiron=寒鐵 +config.basemetals.material.copper=銅 +config.basemetals.material.cupronickel=白銅 +config.basemetals.material.electrum=玫瑰金 +config.basemetals.material.invar=殷鋼 +config.basemetals.material.lead=鉛 +config.basemetals.material.mercury=汞 +config.basemetals.material.mithril=秘銀 +config.basemetals.material.nickel=鎳 +config.basemetals.material.pewter=白鑞 +config.basemetals.material.platinum=白金 +config.basemetals.material.silver=銀 +config.basemetals.material.starsteel=星鋼 +config.basemetals.material.steel=鋼 +config.basemetals.material.tin=錫 +config.basemetals.material.zinc=鋅 +config.basemetals.material.charcoal=木炭 +config.basemetals.material.coal=煤炭 +config.basemetals.material.diamond=鑽石 +config.basemetals.material.emerald=綠寶石 +config.basemetals.material.gold=金 +config.basemetals.material.iron=鐵 +config.basemetals.material.stone=石頭 +config.basemetals.material.wood=木材 +config.basemetals.material.ender=終界 +config.basemetals.material.quartz=石英 +config.basemetals.material.obsidian=黑曜石 +config.basemetals.material.lapis=青金石 +config.basemetals.material.prismarine=海磷石 +config.basemetals.material.redstone=紅石 +config.basemetals.content_mode.high_fantasy.description=保留所有歷史 Base Metals 內容與取得途徑。 +config.basemetals.content_mode.low_fantasy.description=保留幻想材料,但隱藏不合理的裝備與建築配方。 +config.basemetals.content_mode.realism.description=套用低幻想限制,並停用神話材料的一般取得途徑。 diff --git a/src/main/resources/assets/basemetals/recipes/activator_rail.json b/src/main/resources/assets/basemetals/recipes/activator_rail.json index 672be0e3..b210a85a 100644 --- a/src/main/resources/assets/basemetals/recipes/activator_rail.json +++ b/src/main/resources/assets/basemetals/recipes/activator_rail.json @@ -22,7 +22,8 @@ } }, "result": { - "item": "minecraft:activator_rail" + "item": "minecraft:activator_rail", + "count": 6 }, "group": "vanilla" } diff --git a/src/main/resources/assets/basemetals/recipes/detector_rail.json b/src/main/resources/assets/basemetals/recipes/detector_rail.json index 8faeaa38..e7c8d33f 100644 --- a/src/main/resources/assets/basemetals/recipes/detector_rail.json +++ b/src/main/resources/assets/basemetals/recipes/detector_rail.json @@ -6,23 +6,24 @@ "optionValue": "Steel" }], "pattern": [ "x x", - "x/x", + "x-x", "x*x" ], "key": { "x": { "type":"forge:ore_dict", "ore":"ingotSteel" }, - "/": { - "type":"forge:ore_dict", - "ore":"stickWood" + "-": { + "item":"minecraft:stone_pressure_plate" }, "*": { - "item":"minecraft:redstone_torch" + "type":"forge:ore_dict", + "ore":"dustRedstone" } }, "result": { - "item": "minecraft:detector_rail" + "item": "minecraft:detector_rail", + "count": 6 }, "group": "vanilla" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_door.json b/src/main/resources/assets/basemetals/recipes/diamond_door.json index 52434d1d..e14da20a 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_door.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_door.json @@ -6,6 +6,7 @@ "count": 3 }, "pattern": [ + "xx", "xx", "xx" ], diff --git a/src/main/resources/assets/basemetals/recipes/emerald_door.json b/src/main/resources/assets/basemetals/recipes/emerald_door.json index 0207a2fb..d614a11b 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_door.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_door.json @@ -6,6 +6,7 @@ "count": 3 }, "pattern": [ + "xx", "xx", "xx" ], diff --git a/src/main/resources/assets/basemetals/recipes/gold_door.json b/src/main/resources/assets/basemetals/recipes/gold_door.json index 2962b415..2f03b039 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_door.json +++ b/src/main/resources/assets/basemetals/recipes/gold_door.json @@ -6,6 +6,7 @@ "count": 3 }, "pattern": [ + "xx", "xx", "xx" ], diff --git a/src/main/resources/assets/basemetals/recipes/quartz_door.json b/src/main/resources/assets/basemetals/recipes/quartz_door.json index 8a6599d0..98877a53 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_door.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_door.json @@ -6,6 +6,7 @@ "count": 3 }, "pattern": [ + "xx", "xx", "xx" ], diff --git a/src/main/resources/assets/basemetals/recipes/quartz_trapdoor.json b/src/main/resources/assets/basemetals/recipes/quartz_trapdoor.json index 7df31e6b..648544ba 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_trapdoor.json @@ -5,13 +5,12 @@ "data": 0 }, "pattern": [ - "xx", - "xx" + "x" ], "key": { "x": { "type": "forge:ore_dict", - "ore": "gemQuartz" + "ore": "blockQuartz" } }, "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/rail.json b/src/main/resources/assets/basemetals/recipes/rail.json index 26fca752..88753312 100644 --- a/src/main/resources/assets/basemetals/recipes/rail.json +++ b/src/main/resources/assets/basemetals/recipes/rail.json @@ -19,7 +19,8 @@ } }, "result": { - "item": "minecraft:rail" + "item": "minecraft:rail", + "count": 16 }, "group": "vanilla" } diff --git a/src/main/resources/assets/basemetals/textures/blocks/mercury_flow.png.mcmeta b/src/main/resources/assets/basemetals/textures/blocks/mercury_flow.png.mcmeta index de3267f0..4f0718ac 100644 --- a/src/main/resources/assets/basemetals/textures/blocks/mercury_flow.png.mcmeta +++ b/src/main/resources/assets/basemetals/textures/blocks/mercury_flow.png.mcmeta @@ -1,3 +1,3 @@ -{ - "animation": {} +{ + "animation": {} } \ No newline at end of file diff --git a/src/main/resources/assets/basemetals/textures/blocks/mercury_still.png.mcmeta b/src/main/resources/assets/basemetals/textures/blocks/mercury_still.png.mcmeta index 4b721e09..0645f48c 100644 --- a/src/main/resources/assets/basemetals/textures/blocks/mercury_still.png.mcmeta +++ b/src/main/resources/assets/basemetals/textures/blocks/mercury_still.png.mcmeta @@ -1,5 +1,5 @@ -{ - "animation": { - "frametime": 2 - } -} +{ + "animation": { + "frametime": 2 + } +} diff --git a/src/main/resources/assets/minecraft/models/item/acacia_door.json b/src/main/resources/assets/minecraft/models/item/acacia_door.json index 98779c72..575c3683 100644 --- a/src/main/resources/assets/minecraft/models/item/acacia_door.json +++ b/src/main/resources/assets/minecraft/models/item/acacia_door.json @@ -1,7 +1,7 @@ -{ - "parent": "basemetals:item/door_item", - "textures": { - "bottom": "blocks/door_acacia_lower", - "top": "blocks/door_acacia_upper" - } -} +{ + "parent": "basemetals:item/door_item", + "textures": { + "bottom": "blocks/door_acacia_lower", + "top": "blocks/door_acacia_upper" + } +} diff --git a/src/main/resources/assets/minecraft/models/item/birch_door.json b/src/main/resources/assets/minecraft/models/item/birch_door.json index 4e7df906..c36153ff 100644 --- a/src/main/resources/assets/minecraft/models/item/birch_door.json +++ b/src/main/resources/assets/minecraft/models/item/birch_door.json @@ -1,7 +1,7 @@ -{ - "parent": "basemetals:item/door_item", - "textures": { - "bottom": "blocks/door_birch_lower", - "top": "blocks/door_birch_upper" - } -} +{ + "parent": "basemetals:item/door_item", + "textures": { + "bottom": "blocks/door_birch_lower", + "top": "blocks/door_birch_upper" + } +} diff --git a/src/main/resources/assets/minecraft/models/item/dark_oak_door.json b/src/main/resources/assets/minecraft/models/item/dark_oak_door.json index 1df66f76..9d1b4596 100644 --- a/src/main/resources/assets/minecraft/models/item/dark_oak_door.json +++ b/src/main/resources/assets/minecraft/models/item/dark_oak_door.json @@ -1,7 +1,7 @@ -{ - "parent": "basemetals:item/door_item", - "textures": { - "bottom": "blocks/door_dark_oak_lower", - "top": "blocks/door_dark_oak_upper" - } -} +{ + "parent": "basemetals:item/door_item", + "textures": { + "bottom": "blocks/door_dark_oak_lower", + "top": "blocks/door_dark_oak_upper" + } +} diff --git a/src/main/resources/assets/minecraft/models/item/iron_door.json b/src/main/resources/assets/minecraft/models/item/iron_door.json index 2d4793b2..e8369433 100644 --- a/src/main/resources/assets/minecraft/models/item/iron_door.json +++ b/src/main/resources/assets/minecraft/models/item/iron_door.json @@ -1,7 +1,7 @@ -{ - "parent": "basemetals:item/door_item", - "textures": { - "bottom": "blocks/door_iron_lower", - "top": "blocks/door_iron_upper" - } -} +{ + "parent": "basemetals:item/door_item", + "textures": { + "bottom": "blocks/door_iron_lower", + "top": "blocks/door_iron_upper" + } +} diff --git a/src/main/resources/assets/minecraft/models/item/jungle_door.json b/src/main/resources/assets/minecraft/models/item/jungle_door.json index b927991b..cd8bab03 100644 --- a/src/main/resources/assets/minecraft/models/item/jungle_door.json +++ b/src/main/resources/assets/minecraft/models/item/jungle_door.json @@ -1,7 +1,7 @@ -{ - "parent": "basemetals:item/door_item", - "textures": { - "bottom": "blocks/door_jungle_lower", - "top": "blocks/door_jungle_upper" - } -} +{ + "parent": "basemetals:item/door_item", + "textures": { + "bottom": "blocks/door_jungle_lower", + "top": "blocks/door_jungle_upper" + } +} diff --git a/src/main/resources/assets/minecraft/models/item/oak_door.json b/src/main/resources/assets/minecraft/models/item/oak_door.json index 3b9c8758..13d6a1f5 100644 --- a/src/main/resources/assets/minecraft/models/item/oak_door.json +++ b/src/main/resources/assets/minecraft/models/item/oak_door.json @@ -1,7 +1,7 @@ -{ - "parent": "basemetals:item/door_item", - "textures": { - "bottom": "blocks/door_wood_lower", - "top": "blocks/door_wood_upper" - } -} +{ + "parent": "basemetals:item/door_item", + "textures": { + "bottom": "blocks/door_wood_lower", + "top": "blocks/door_wood_upper" + } +} diff --git a/src/main/resources/assets/minecraft/models/item/spruce_door.json b/src/main/resources/assets/minecraft/models/item/spruce_door.json index 78fc3e09..ee5e65e9 100644 --- a/src/main/resources/assets/minecraft/models/item/spruce_door.json +++ b/src/main/resources/assets/minecraft/models/item/spruce_door.json @@ -1,7 +1,7 @@ -{ - "parent": "basemetals:item/door_item", - "textures": { - "bottom": "blocks/door_spruce_lower", - "top": "blocks/door_spruce_upper" - } -} +{ + "parent": "basemetals:item/door_item", + "textures": { + "bottom": "blocks/door_spruce_lower", + "top": "blocks/door_spruce_upper" + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreenTest.java b/src/test/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreenTest.java new file mode 100644 index 00000000..86593289 --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreenTest.java @@ -0,0 +1,78 @@ +package com.mcmoddev.basemetals.client.config; + +import com.mcmoddev.basemetals.util.BMeConfig; +import com.mcmoddev.basemetals.util.TestConfigFactory; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.fml.client.config.IConfigElement; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class BaseMetalsConfigScreenTest { + @TempDir + Path tempDirectory; + + @Test + void rootContainsOnlyTheFiveHistoricalCategoriesInStableOrder() { + final Configuration configuration = create(); + final List elements = BaseMetalsConfigScreen.categoryElements(configuration); + assertEquals(BMeConfig.GUI_CATEGORIES.size(), elements.size()); + for (int index = 0; index < elements.size(); index++) { + assertEquals(BMeConfig.GUI_CATEGORIES.get(index).toLowerCase(java.util.Locale.ROOT), + elements.get(index).getName()); + assertFalse(elements.get(index).isProperty()); + assertTrue(elements.get(index).requiresMcRestart()); + assertEquals(BaseMetalsConfigScreen.CategoryEntry.class, + elements.get(index).getConfigEntryClass()); + } + } + + @Test + void warningReportsOnlyNewlyDisabledGeneratedMaterials() { + final Configuration configuration = create(); + final Map before = BaseMetalsConfigScreen.snapshot(configuration); + configuration.getCategory(BMeConfig.MATERIALS_CAT).get("EnableColdiron").set(false); + configuration.getCategory(BMeConfig.MATERIALS_CAT).get("EnableTin").set(false); + configuration.getCategory(BMeConfig.MATERIALS_CAT).get("EnableAntimony").set(false); + + assertEquals(java.util.Arrays.asList( + "basemetals:legacy/coldiron_ore", "basemetals:legacy/tin_ore"), + BaseMetalsConfigScreen.disabledGeneratedRules(before, configuration)); + + BaseMetalsConfigScreen.restore(before, configuration); + assertTrue(configuration.getCategory(BMeConfig.MATERIALS_CAT) + .get("EnableColdiron").getBoolean()); + assertTrue(BaseMetalsConfigScreen.disabledGeneratedRules(before, configuration).isEmpty()); + } + + @Test + void disposableConfigurationPersistsDoneValuesWhileRestoreModelsEscape() { + final Configuration configuration = create(); + final Map before = BaseMetalsConfigScreen.snapshot(configuration); + configuration.getCategory(BMeConfig.VANILLA_CAT).get("EnableGold").set(false); + configuration.getCategory(BMeConfig.GENERAL_CAT) + .get(BMeConfig.CONTENT_MODE_PROPERTY).set("realism"); + configuration.save(); + + final Configuration reloaded = create(); + assertFalse(reloaded.getCategory(BMeConfig.VANILLA_CAT).get("EnableGold").getBoolean()); + assertEquals("realism", reloaded.getCategory(BMeConfig.GENERAL_CAT) + .get(BMeConfig.CONTENT_MODE_PROPERTY).getString()); + + BaseMetalsConfigScreen.restore(before, configuration); + assertTrue(configuration.getCategory(BMeConfig.VANILLA_CAT).get("EnableGold").getBoolean()); + assertEquals("high_fantasy", configuration.getCategory(BMeConfig.GENERAL_CAT) + .get(BMeConfig.CONTENT_MODE_PROPERTY).getString()); + } + + private Configuration create() { + return TestConfigFactory.create(tempDirectory.resolve("BaseMetals.cfg").toFile()); + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/client/config/ClientExtensionRegistrationContractTest.java b/src/test/java/com/mcmoddev/basemetals/client/config/ClientExtensionRegistrationContractTest.java new file mode 100644 index 00000000..58f526a3 --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/client/config/ClientExtensionRegistrationContractTest.java @@ -0,0 +1,39 @@ +package com.mcmoddev.basemetals.client.config; + +import org.junit.jupiter.api.Test; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ClientExtensionRegistrationContractTest { + @Test + void registersExactlyOneConventionalBaseMetalsExtensionFromTheClientProxy() throws Exception { + final Path clientProxy = Paths.get("src", "main", "java", "com", "mcmoddev", + "basemetals", "proxy", "ClientProxy.java"); + final String source = new String(Files.readAllBytes(clientProxy), StandardCharsets.UTF_8); + assertEquals(1, occurrences(source, + "WorldSettingsExtensionRegistry.registerConfigScreen")); + assertTrue(source.contains("BaseMetals.MODID")); + assertTrue(source.contains("BaseMetalsConfigScreen::new")); + + final Path commonProxy = clientProxy.resolveSibling("CommonProxy.java"); + final String commonSource = new String(Files.readAllBytes(commonProxy), StandardCharsets.UTF_8); + assertFalse(commonSource.contains("WorldSettingsExtensionRegistry")); + assertFalse(commonSource.contains("BaseMetalsConfigScreen")); + } + + private static int occurrences(final String source, final String value) { + int count = 0; + for (int index = 0; (index = source.indexOf(value, index)) >= 0; + index += value.length()) { + count++; + } + return count; + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/client/config/ConfigLocalizationContractTest.java b/src/test/java/com/mcmoddev/basemetals/client/config/ConfigLocalizationContractTest.java new file mode 100644 index 00000000..949aa86b --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/client/config/ConfigLocalizationContractTest.java @@ -0,0 +1,111 @@ +package com.mcmoddev.basemetals.client.config; + +import org.junit.jupiter.api.Test; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.HashSet; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ConfigLocalizationContractTest { + private static final Set STANDARD_ENGLISH_LOCALES = new HashSet<>(Arrays.asList( + "en_au.lang", "en_ca.lang", "en_en.lang", "en_gb.lang", "en_us.lang")); + private static final List MATERIALS = Arrays.asList( + "adamantine", "antimony", "aquarium", "bismuth", "brass", "bronze", + "coldiron", "copper", "cupronickel", "electrum", "invar", "lead", + "mercury", "mithril", "nickel", "pewter", "platinum", "silver", + "starsteel", "steel", "tin", "zinc", "charcoal", "coal", "diamond", + "emerald", "gold", "iron", "stone", "wood", "ender", "quartz", + "obsidian", "lapis", "prismarine", "redstone"); + + @Test + void allEighteenLocalesDefineTheCompleteConfigurationVocabulary() throws Exception { + final Path langDirectory = Paths.get("src", "main", "resources", "assets", + "basemetals", "lang"); + final List locales; + try (java.util.stream.Stream files = Files.list(langDirectory)) { + locales = files.filter(path -> path.getFileName().toString().endsWith(".lang")) + .sorted().collect(java.util.stream.Collectors.toList()); + } + assertEquals(18, locales.size()); + final Map english = configurationValues( + langDirectory.resolve("en_us.lang")); + assertEquals(64, english.size()); + + for (final Path locale : locales) { + final String text = new String(Files.readAllBytes(locale), StandardCharsets.UTF_8); + final Map values = configurationValues(locale); + assertEquals(english.keySet(), values.keySet(), locale.toString()); + for (final String key : Arrays.asList( + "config.basemetals.title=", "config.basemetals.restart_guidance=", + "config.basemetals.category.general=", + "config.basemetals.category.metals=", + "config.basemetals.category.vanilla=", + "config.basemetals.category.fluids=", + "config.basemetals.category.forced_traits=", + "config.basemetals.option.achievements=", + "config.basemetals.option.content_mode=", + "config.basemetals.option.content_mode.tooltip=", + "config.basemetals.content_mode.high_fantasy=", + "config.basemetals.content_mode.high_fantasy.description=", + "config.basemetals.content_mode.low_fantasy=", + "config.basemetals.content_mode.low_fantasy.description=", + "config.basemetals.content_mode.realism=", + "config.basemetals.content_mode.realism.description=", + "config.basemetals.warning.content_mode.title=", + "config.basemetals.warning.content_mode.message=", + "config.basemetals.warning.content_mode.realism=", + "config.basemetals.warning.confirm=", + "config.basemetals.warning.disable_ores.title=", + "config.basemetals.warning.disable_ores.message=", + "config.basemetals.warning.disable_ores.confirm=")) { + assertEquals(1, occurrences(text, key), locale + " " + key); + } + for (final String material : MATERIALS) { + final String key = "config.basemetals.material." + material + "="; + assertEquals(1, occurrences(text, key), locale + " " + key); + } + assertTrue(text.contains("config.basemetals.category.metals.tooltip="), + locale.toString()); + if (!STANDARD_ENGLISH_LOCALES.contains(locale.getFileName().toString())) { + final long translated = english.entrySet().stream() + .filter(entry -> !entry.getValue().equals(values.get(entry.getKey()))) + .count(); + assertTrue(translated >= 20, + locale + " still contains an English fallback configuration block"); + } + } + } + + private static Map configurationValues(final Path locale) + throws Exception { + final Map values = new LinkedHashMap<>(); + for (final String line : Files.readAllLines(locale, StandardCharsets.UTF_8)) { + if (!line.startsWith("config.basemetals.")) { + continue; + } + final int separator = line.indexOf('='); + assertTrue(separator > 0, locale + " malformed configuration translation: " + line); + values.put(line.substring(0, separator), line.substring(separator + 1)); + } + return values; + } + + private static int occurrences(final String text, final String value) { + int count = 0; + for (int index = 0; (index = text.indexOf(value, index)) >= 0; + index += value.length()) { + count++; + } + return count; + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/client/renderer/BoltRendererContractTest.java b/src/test/java/com/mcmoddev/basemetals/client/renderer/BoltRendererContractTest.java new file mode 100644 index 00000000..25473cde --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/client/renderer/BoltRendererContractTest.java @@ -0,0 +1,69 @@ +package com.mcmoddev.basemetals.client.renderer; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import net.minecraft.util.ResourceLocation; + +import org.junit.jupiter.api.Test; + +/** Locks the texture used by Base Metals' in-world bolt renderer. */ +final class BoltRendererContractTest { + + private static final ResourceLocation VANILLA_PROJECTILE_TEXTURE = + new ResourceLocation("minecraft", "textures/entity/projectiles/arrow.png"); + + @Test + void boltRendererUsesAnExistingVanillaProjectileTexture() { + assertEquals(VANILLA_PROJECTILE_TEXTURE, + new RenderBaseMetalsBolt(null).getEntityTexture(null)); + assertNotNull(RenderBaseMetalsBolt.class.getClassLoader().getResource( + "assets/minecraft/textures/entity/projectiles/arrow.png"), + "Selected projectile texture is absent from the Minecraft client"); + } + + @Test + void everyBoltItemModelRetainsItsMaterialTexture() throws IOException { + final Path modelDirectory = Paths.get( + "src/main/resources/assets/basemetals/models/item"); + final Path textureDirectory = Paths.get( + "src/main/resources/assets/basemetals/textures/items"); + final List models; + try (Stream files = Files.list(modelDirectory)) { + models = files.filter(path -> path.getFileName().toString().endsWith("_bolt.json")) + .sorted().collect(Collectors.toList()); + } + + assertEquals(27, models.size(), "Unexpected Base Metals bolt model count"); + for (final Path modelPath : models) { + final String fileName = modelPath.getFileName().toString(); + final String itemName = fileName.substring(0, fileName.length() - ".json".length()); + final JsonObject model = new JsonParser().parse(new String( + Files.readAllBytes(modelPath), StandardCharsets.UTF_8)).getAsJsonObject(); + assertEquals("item/generated", model.get("parent").getAsString(), fileName); + assertEquals("basemetals:items/" + itemName, + model.getAsJsonObject("textures").get("layer0").getAsString(), fileName); + + final Path texturePath = textureDirectory.resolve(itemName + ".png"); + assertTrue(Files.isRegularFile(texturePath), "Missing texture for " + fileName); + final BufferedImage texture = javax.imageio.ImageIO.read(texturePath.toFile()); + assertNotNull(texture, "Unreadable texture for " + fileName); + assertEquals(16, texture.getWidth(), fileName); + assertEquals(16, texture.getHeight(), fileName); + } + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/content/ContentPolicyTest.java b/src/test/java/com/mcmoddev/basemetals/content/ContentPolicyTest.java new file mode 100644 index 00000000..5270244e --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/content/ContentPolicyTest.java @@ -0,0 +1,157 @@ +package com.mcmoddev.basemetals.content; + +import com.mcmoddev.basemetals.data.MaterialNames; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ContentPolicyTest { + private static final Set ALL_MATERIALS = set( + "adamantine", "antimony", "aquarium", "bismuth", "brass", "bronze", + "charcoal", "coal", "coldiron", "copper", "cupronickel", "diamond", + "electrum", "emerald", "ender", "gold", "invar", "iron", "lapis", + "lead", "mercury", "mithril", "nickel", "obsidian", "pewter", + "platinum", "prismarine", "quartz", "redstone", "silver", + "starsteel", "steel", "stone", "tin", "wood", "zinc"); + private static final Set MYTHICAL = set("adamantine", "aquarium", "coldiron", + "mithril", "starsteel"); + private static final Set FULL_TOOLS = set("adamantine", "aquarium", "bronze", + "coldiron", "copper", "cupronickel", "invar", "mithril", "nickel", + "starsteel", "steel", "iron"); + private static final Set ARMOR = set("adamantine", "aquarium", "brass", + "bronze", "coldiron", "copper", "cupronickel", "electrum", "invar", + "mithril", "nickel", "platinum", "silver", "starsteel", "steel", + "iron", "gold", "diamond"); + private static final Set AMMO = union(FULL_TOOLS, + set("silver", "obsidian", "diamond")); + private static final Set GEARS = set("adamantine", "aquarium", "brass", + "bronze", "coldiron", "copper", "cupronickel", "invar", "mithril", + "nickel", "starsteel", "steel", "iron", "gold", "wood"); + private static final Set TOOL_FORMS = EnumSet.of(MaterialForm.AXE, + MaterialForm.CRACKHAMMER, MaterialForm.HOE, MaterialForm.PICKAXE, + MaterialForm.SCYTHE, MaterialForm.SHEARS, MaterialForm.SHOVEL, + MaterialForm.SWORD); + private static final Set ARMOR_FORMS = EnumSet.of(MaterialForm.BOOTS, + MaterialForm.CHESTPLATE, MaterialForm.HELMET, MaterialForm.LEGGINGS, + MaterialForm.HORSE_ARMOR, MaterialForm.SHIELD); + + @Test + void highFantasyAllowsEveryMaterialAndForm() { + final ContentPolicy policy = ContentPolicy.forMode(ContentMode.HIGH_FANTASY); + for (final String material : ALL_MATERIALS) { + for (final MaterialForm form : MaterialForm.values()) { + assertTrue(policy.allows(material, form), material + "/" + form); + } + } + } + + @Test + void everyRestrictedModeMaterialAndFormDecisionMatchesTheReviewedMatrix() { + for (final ContentMode mode : Arrays.asList(ContentMode.LOW_FANTASY, ContentMode.REALISM)) { + final ContentPolicy policy = ContentPolicy.forMode(mode); + for (final String material : ALL_MATERIALS) { + for (final MaterialForm form : MaterialForm.values()) { + assertTrue(policy.allows(material, form) == expected(mode, material, form), + mode + " " + material + "/" + form); + } + } + } + } + + @Test + void restrictedModesApplyTheReviewedEquipmentMatrix() { + final ContentPolicy low = ContentPolicy.forMode(ContentMode.LOW_FANTASY); + assertFalse(low.allows(MaterialNames.ADAMANTINE, MaterialForm.BOW)); + assertTrue(low.allows(MaterialNames.ADAMANTINE, MaterialForm.PICKAXE)); + assertFalse(low.allows(MaterialNames.PEWTER, MaterialForm.CHESTPLATE)); + assertTrue(low.allows(MaterialNames.BRASS, MaterialForm.CHESTPLATE)); + assertTrue(low.allows(MaterialNames.SILVER, MaterialForm.SWORD)); + assertFalse(low.allows(MaterialNames.SILVER, MaterialForm.PICKAXE)); + assertTrue(low.allows(MaterialNames.OBSIDIAN, MaterialForm.SCYTHE)); + assertFalse(low.allows(MaterialNames.OBSIDIAN, MaterialForm.HOE)); + assertTrue(low.allows(MaterialNames.DIAMOND, MaterialForm.CRACKHAMMER)); + assertTrue(low.allows(MaterialNames.IRON, MaterialForm.SHIELD)); + assertFalse(low.allows(MaterialNames.TIN, MaterialForm.GEAR)); + } + + @Test + void realismRemovesAllNormalAcquisitionForTheFiveMythicalMaterials() { + final ContentPolicy realism = ContentPolicy.forMode(ContentMode.REALISM); + for (final String material : Arrays.asList(MaterialNames.ADAMANTINE, + MaterialNames.AQUARIUM, MaterialNames.COLDIRON, MaterialNames.MITHRIL, + MaterialNames.STARSTEEL)) { + for (final MaterialForm form : MaterialForm.values()) { + assertFalse(realism.allows(material, form), material + "/" + form); + } + assertFalse(realism.defaultsOreEnabled(material)); + } + assertTrue(realism.defaultsOreEnabled(MaterialNames.COPPER)); + } + + @Test + void mercuryRetainsOnlyTheExplicitProcessingForms() { + final ContentPolicy low = ContentPolicy.forMode(ContentMode.LOW_FANTASY); + final ContentPolicy realism = ContentPolicy.forMode(ContentMode.REALISM); + assertTrue(low.allows(MaterialNames.MERCURY, MaterialForm.INGOT)); + assertFalse(realism.allows(MaterialNames.MERCURY, MaterialForm.INGOT)); + assertTrue(realism.allows(MaterialNames.MERCURY, MaterialForm.ORE)); + assertTrue(realism.allows(MaterialNames.MERCURY, MaterialForm.POWDER)); + assertTrue(realism.allows(MaterialNames.MERCURY, MaterialForm.FLUID)); + assertFalse(low.allows(MaterialNames.MERCURY, MaterialForm.BLOCK)); + assertFalse(realism.allows(MaterialNames.MERCURY, MaterialForm.SWORD)); + } + + @Test + void compoundRegistrySuffixesResolveToTheMostSpecificForm() { + assertTrue(MaterialForm.fromRegistryPath("nickel_dense_plate") == MaterialForm.DENSE_PLATE); + assertTrue(MaterialForm.fromRegistryPath("nickel_powder_dirty") == MaterialForm.DIRTY_POWDER); + assertTrue(MaterialForm.fromRegistryPath("nickel_crushed_purified") == MaterialForm.CRUSHED_PURIFIED); + assertTrue(MaterialForm.fromRegistryPath("nickel_pressure_plate") == MaterialForm.PRESSURE_PLATE); + } + + private static boolean expected(final ContentMode mode, final String material, + final MaterialForm form) { + if (mode == ContentMode.REALISM && MYTHICAL.contains(material)) return false; + if (form == MaterialForm.OTHER) return !"mercury".equals(material); + if (form == MaterialForm.BOW || form == MaterialForm.CROSSBOW + || form == MaterialForm.FISHING_ROD) return false; + if (TOOL_FORMS.contains(form)) { + if (FULL_TOOLS.contains(material)) return true; + if ("silver".equals(material)) return form == MaterialForm.SWORD; + if ("obsidian".equals(material)) return form == MaterialForm.AXE + || form == MaterialForm.SWORD || form == MaterialForm.SCYTHE; + if ("diamond".equals(material)) return form == MaterialForm.CRACKHAMMER + || form == MaterialForm.SCYTHE || form == MaterialForm.SHEARS; + if ("stone".equals(material)) return form == MaterialForm.CRACKHAMMER + || form == MaterialForm.SCYTHE; + return "wood".equals(material) && form == MaterialForm.CRACKHAMMER; + } + if (ARMOR_FORMS.contains(form)) return ARMOR.contains(material); + if (form == MaterialForm.ARROW || form == MaterialForm.BOLT) return AMMO.contains(material); + if (form == MaterialForm.GEAR) return GEARS.contains(material); + if (form == MaterialForm.ANVIL) return "stone".equals(material) + || "steel".equals(material) + || (mode == ContentMode.LOW_FANTASY && "adamantine".equals(material)); + if ("mercury".equals(material)) return form == MaterialForm.ORE + || form == MaterialForm.POWDER || form == MaterialForm.SMALLPOWDER + || form == MaterialForm.FLUID + || (mode == ContentMode.LOW_FANTASY && form == MaterialForm.INGOT); + return true; + } + + private static Set set(final String... values) { + return new HashSet<>(Arrays.asList(values)); + } + + private static Set union(final Set first, final Set second) { + final Set result = new HashSet<>(first); + result.addAll(second); + return result; + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/data/DoorRecipeContractTest.java b/src/test/java/com/mcmoddev/basemetals/data/DoorRecipeContractTest.java new file mode 100644 index 00000000..d859b933 --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/data/DoorRecipeContractTest.java @@ -0,0 +1,112 @@ +package com.mcmoddev.basemetals.data; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.io.Reader; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +class DoorRecipeContractTest { + + private static final Path RECIPES = Paths.get( + "src", "main", "resources", "assets", "basemetals", "recipes"); + + @Test + void doorsAndTrapdoorsHaveDistinctCanonicalRecipes() throws IOException { + final List collisions = new ArrayList<>(); + final List invalidDoorShapes = new ArrayList<>(); + final List invalidTrapdoorShapes = new ArrayList<>(); + final List invalidTrapdoorIngredients = new ArrayList<>(); + final List invalidYields = new ArrayList<>(); + int pairs = 0; + + try (DirectoryStream doors = Files.newDirectoryStream(RECIPES, "*_door.json")) { + for (final Path doorPath : doors) { + final String fileName = doorPath.getFileName().toString(); + final String material = fileName.substring(0, fileName.length() - "_door.json".length()); + final Path trapdoorPath = RECIPES.resolve(material + "_trapdoor.json"); + assertTrue(Files.isRegularFile(trapdoorPath), + "Missing trapdoor recipe for " + material); + + final JsonObject door = read(doorPath); + final JsonObject trapdoor = read(trapdoorPath); + final List doorPattern = pattern(door); + final List trapdoorPattern = pattern(trapdoor); + + if (doorPattern.equals(trapdoorPattern) + && ingredient(door).equals(ingredient(trapdoor))) { + collisions.add(material); + } + if (!doorPattern.equals(Arrays.asList("xx", "xx", "xx"))) { + invalidDoorShapes.add(material + "=" + String.join("/", doorPattern)); + } + final List expectedTrapdoorPattern = "quartz".equals(material) + ? Collections.singletonList("x") : Arrays.asList("xx", "xx"); + if (!trapdoorPattern.equals(expectedTrapdoorPattern)) { + invalidTrapdoorShapes.add(material + "=" + String.join("/", trapdoorPattern)); + } + final String expectedTrapdoorOre = "quartz".equals(material) + ? "blockQuartz" : ingredient(door).get("ore").getAsString(); + if (!expectedTrapdoorOre.equals(ingredient(trapdoor).get("ore").getAsString())) { + invalidTrapdoorIngredients.add(material + "=" + ingredient(trapdoor)); + } + if (resultCount(door) != 3 || resultCount(trapdoor) != 1) { + invalidYields.add(material + "=door:" + resultCount(door) + + ",trapdoor:" + resultCount(trapdoor)); + } + pairs++; + } + } + + assertEquals(26, pairs, "Unexpected number of door/trapdoor recipe pairs"); + assertEquals(Collections.emptyList(), collisions, + "Door and trapdoor recipes must not have identical inputs"); + assertEquals(Collections.emptyList(), invalidDoorShapes, + "Doors must use six materials in the canonical 2x3 pattern"); + assertEquals(Collections.emptyList(), invalidTrapdoorShapes, + "Trapdoors must use their canonical non-conflicting pattern"); + assertEquals(Collections.emptyList(), invalidTrapdoorIngredients, + "Trapdoor ingredients changed"); + assertEquals(Collections.emptyList(), invalidYields, + "Door and trapdoor crafting yields changed"); + } + + private static JsonObject read(final Path path) throws IOException { + try (Reader reader = Files.newBufferedReader(path)) { + return new JsonParser().parse(reader).getAsJsonObject(); + } + } + + private static List pattern(final JsonObject recipe) { + final List result = new ArrayList<>(); + final JsonArray pattern = recipe.getAsJsonArray("pattern"); + for (final JsonElement row : pattern) { + result.add(row.getAsString()); + } + return result; + } + + private static JsonObject ingredient(final JsonObject recipe) { + return recipe.getAsJsonObject("key").getAsJsonObject("x"); + } + + private static int resultCount(final JsonObject recipe) { + final JsonObject result = recipe.getAsJsonObject("result"); + return result.has("count") ? result.get("count").getAsInt() : 1; + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/data/LootPolicyContractTest.java b/src/test/java/com/mcmoddev/basemetals/data/LootPolicyContractTest.java new file mode 100644 index 00000000..2b90f5a8 --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/data/LootPolicyContractTest.java @@ -0,0 +1,66 @@ +package com.mcmoddev.basemetals.data; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.junit.jupiter.api.Test; + +import java.io.Reader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class LootPolicyContractTest { + @Test + void everyBaseMetalsAuxiliaryLootEntryUsesTheContentPolicyCondition() throws Exception { + final Path root = Paths.get("src", "main", "resources", "assets", "basemetals", "alt", "chests"); + final AtomicInteger checked = new AtomicInteger(); + try (java.util.stream.Stream files = Files.list(root)) { + for (final Path file : (Iterable) files.filter(path -> path.toString().endsWith(".json"))::iterator) { + try (Reader reader = Files.newBufferedReader(file)) { + visit(new JsonParser().parse(reader), file, checked); + } + } + } + assertTrue(checked.get() > 500, "Expected the complete legacy auxiliary-loot inventory"); + } + + private static void visit(final JsonElement element, final Path file, + final AtomicInteger checked) { + if (element.isJsonArray()) { + for (final JsonElement child : element.getAsJsonArray()) { + visit(child, file, checked); + } + return; + } + if (!element.isJsonObject()) { + return; + } + final JsonObject object = element.getAsJsonObject(); + if (object.has("type") && "item".equals(object.get("type").getAsString()) + && object.has("name") + && object.get("name").getAsString().startsWith("basemetals:")) { + final JsonArray conditions = object.getAsJsonArray("conditions"); + assertTrue(conditions != null, file + " " + object.get("name")); + int matches = 0; + for (final JsonElement condition : conditions) { + final JsonObject value = condition.getAsJsonObject(); + if (value.has("condition") + && "basemetals:content_policy".equals(value.get("condition").getAsString())) { + matches++; + assertEquals(object.get("name").getAsString(), value.get("item").getAsString()); + } + } + assertEquals(1, matches, file + " " + object.get("name")); + checked.incrementAndGet(); + } + for (final java.util.Map.Entry child : object.entrySet()) { + visit(child.getValue(), file, checked); + } + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/data/OreSpawnProviderContractTest.java b/src/test/java/com/mcmoddev/basemetals/data/OreSpawnProviderContractTest.java new file mode 100644 index 00000000..38f8eef6 --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/data/OreSpawnProviderContractTest.java @@ -0,0 +1,203 @@ +package com.mcmoddev.basemetals.data; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.io.Reader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import com.mcmoddev.basemetals.content.ContentMode; +import com.mcmoddev.basemetals.content.ContentPolicy; +import com.mcmoddev.basemetals.worldgen.BaseMetalsWorldgenProvider; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +class OreSpawnProviderContractTest { + + private static final Path DISABLED_EXAMPLE = java.nio.file.Paths.get( + "docs", "examples", "basemetals-orespawn-disabled.json"); + + @Test + void nativeProviderMatchesTheStableTranslatedContract() { + final JsonObject provider = BaseMetalsWorldgenProvider + .build(ContentPolicy.forMode(ContentMode.HIGH_FANTASY)).toJson(); + assertProviderIdentity(provider); + + final JsonObject ores = provider.getAsJsonObject("ores"); + assertEquals(expectedRules().keySet(), keys(ores)); + for (final Map.Entry expected : expectedRules().entrySet()) { + assertRule(ores.getAsJsonObject(expected.getKey()), expected.getKey(), expected.getValue(), true); + } + } + + @Test + void contentModesOnlyChangeTheThreeFreshWorldFantasyDefaults() { + final JsonObject high = provider(ContentMode.HIGH_FANTASY); + final JsonObject low = provider(ContentMode.LOW_FANTASY); + final JsonObject realism = provider(ContentMode.REALISM); + for (final String id : expectedRules().keySet()) { + assertTrue(high.getAsJsonObject("ores").getAsJsonObject(id).get("enabled").getAsBoolean(), id); + assertTrue(low.getAsJsonObject("ores").getAsJsonObject(id).get("enabled").getAsBoolean(), id); + final boolean mythical = id.contains("adamantine") || id.contains("coldiron") + || id.contains("starsteel"); + assertEquals(!mythical, realism.getAsJsonObject("ores").getAsJsonObject(id) + .get("enabled").getAsBoolean(), id); + } + } + + @Test + void disabledExampleRetainsEveryRuleButDisablesAllOfThem() throws IOException { + final JsonObject example = read(DISABLED_EXAMPLE); + assertProviderIdentity(example); + + final JsonObject ores = example.getAsJsonObject("ores"); + assertEquals(expectedRules().keySet(), keys(ores)); + for (final Map.Entry expected : expectedRules().entrySet()) { + assertRule(ores.getAsJsonObject(expected.getKey()), expected.getKey(), expected.getValue(), false); + } + } + + private static void assertProviderIdentity(final JsonObject provider) { + assertEquals(5, provider.get("schema_version").getAsInt()); + assertEquals("basemetals", provider.get("provider_modid").getAsString()); + assertEquals(2, provider.get("provider_revision").getAsInt()); + assertTrue(provider.get("merge_new_entries_into_existing_worlds").getAsBoolean()); + assertTrue(provider.getAsJsonObject("rocks").entrySet().isEmpty()); + for (final String section : Arrays.asList("fluid_deposits", "geomes", "biome_rules", + "terrain_dimensions", "biome_palettes", "dimension_materials", "templates")) { + assertTrue(provider.getAsJsonObject(section).entrySet().isEmpty(), section + " must remain empty"); + } + } + + private static void assertRule(final JsonObject rule, final String id, + final Rule expected, final boolean enabled) { + assertEquals(enabled, rule.get("enabled").getAsBoolean(), id); + assertEquals("basemetals:" + expected.ore, rule.get("block").getAsString(), id); + assertFalse(rule.get("native_generation").getAsBoolean(), id); + assertFalse(rule.get("retrogen").getAsBoolean(), id); + + final JsonArray outputs = rule.getAsJsonArray("outputs"); + assertEquals(1, outputs.size(), id); + assertEquals("basemetals:" + expected.ore, + outputs.get(0).getAsJsonObject().get("block").getAsString(), id); + assertEquals(100, outputs.get(0).getAsJsonObject().get("weight").getAsInt(), id); + assertEquals(-2048, outputs.get(0).getAsJsonObject().get("min_y").getAsInt(), id); + assertEquals(2048, outputs.get(0).getAsJsonObject().get("max_y").getAsInt(), id); + + final String containerName = expected.dimension.startsWith("minecraft:") + ? "dimensions" : "dimension_selectors"; + final JsonObject settings = rule.getAsJsonObject(containerName) + .getAsJsonObject(expected.dimension); + assertTrue(settings.get("enabled").getAsBoolean(), id); + assertEquals(expected.minY, settings.get("min_y").getAsInt(), id); + assertEquals(expected.maxY, settings.get("max_y").getAsInt(), id); + assertEquals(expected.frequency, settings.get("frequency").getAsDouble(), 0.0D, id); + assertEquals(4, settings.get("min_quantity").getAsInt(), id); + assertEquals(11, settings.get("max_quantity").getAsInt(), id); + assertEquals("default", settings.get("pattern").getAsString(), id); + assertEquals("orespawn:standard", settings.get("placement_channel").getAsString(), id); + assertEquals("uniform", settings.get("height_distribution").getAsString(), id); + assertEquals(0.0D, settings.get("discard_chance_on_air_exposure").getAsDouble(), 0.0D, id); + assertEquals(8, settings.get("spread").getAsInt(), id); + assertEquals(4, settings.get("vertical_spread").getAsInt(), id); + assertEquals(8, settings.get("node_size").getAsInt(), id); + assertEquals(Arrays.asList("minecraft:stone", "minecraft:netherrack", "minecraft:end_stone"), + weightedIds(settings.getAsJsonArray("host_blocks"), "block"), id); + for (final String empty : Arrays.asList("host_tags", "host_families", "biome_ids", + "excluded_biome_ids", "biome_dictionary", "excluded_biome_dictionary")) { + assertTrue(settings.getAsJsonArray(empty).size() == 0, id + " " + empty); + } + assertTrue(settings.getAsJsonObject("geomes").entrySet().isEmpty(), id); + } + + private static JsonObject provider(final ContentMode mode) { + return BaseMetalsWorldgenProvider.build(ContentPolicy.forMode(mode)).toJson(); + } + + private static Map expectedRules() { + final Map result = new LinkedHashMap<>(); + result.put("basemetals:legacy/coldiron_ore", + new Rule("coldiron_ore", "minecraft:the_nether", 0, 127, 5.0D)); + result.put("basemetals:legacy/adamantine_ore", + new Rule("adamantine_ore", "minecraft:the_nether", 0, 127, 2.0D)); + result.put("basemetals:legacy/starsteel_ore", + new Rule("starsteel_ore", "minecraft:the_end", 0, 254, 5.0D)); + result.put("basemetals:legacy/copper_ore", + new Rule("copper_ore", "orespawn:all_except_nether_end", 0, 95, 10.0D)); + result.put("basemetals:legacy/silver_ore", + new Rule("silver_ore", "orespawn:all_except_nether_end", 0, 31, 4.0D)); + result.put("basemetals:legacy/tin_ore", + new Rule("tin_ore", "orespawn:all_except_nether_end", 0, 127, 10.0D)); + result.put("basemetals:legacy/lead_ore", + new Rule("lead_ore", "orespawn:all_except_nether_end", 0, 63, 5.0D)); + result.put("basemetals:legacy/zinc_ore", + new Rule("zinc_ore", "orespawn:all_except_nether_end", 0, 95, 5.0D)); + result.put("basemetals:legacy/mercury_ore", + new Rule("mercury_ore", "orespawn:all_except_nether_end", 0, 31, 3.0D)); + result.put("basemetals:legacy/nickel_ore", + new Rule("nickel_ore", "orespawn:all_except_nether_end", 32, 95, 1.0D)); + result.put("basemetals:legacy/platinum_ore", + new Rule("platinum_ore", "orespawn:all_except_nether_end", 1, 31, 0.125D)); + return Collections.unmodifiableMap(result); + } + + private static java.util.List strings(final JsonArray values) { + final java.util.List result = new java.util.ArrayList<>(); + for (final JsonElement value : values) { + result.add(value.getAsString()); + } + return result; + } + + private static java.util.List weightedIds(final JsonArray values, final String key) { + final java.util.List result = new java.util.ArrayList<>(); + for (final JsonElement value : values) { + result.add(value.isJsonPrimitive() ? value.getAsString() + : value.getAsJsonObject().get(key).getAsString()); + } + return result; + } + + private static java.util.Set keys(final JsonObject object) { + final java.util.Set result = new java.util.LinkedHashSet<>(); + for (final Map.Entry entry : object.entrySet()) { + result.add(entry.getKey()); + } + return result; + } + + private static JsonObject read(final Path path) throws IOException { + assertTrue(Files.isRegularFile(path), "Missing JSON contract " + path); + try (Reader reader = Files.newBufferedReader(path)) { + return new JsonParser().parse(reader).getAsJsonObject(); + } + } + + private static final class Rule { + private final String ore; + private final String dimension; + private final int minY; + private final int maxY; + private final double frequency; + + private Rule(final String ore, final String dimension, + final int minY, final int maxY, final double frequency) { + this.ore = ore; + this.dimension = dimension; + this.minY = minY; + this.maxY = maxY; + this.frequency = frequency; + } + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/data/RailRecipeAdvancementTest.java b/src/test/java/com/mcmoddev/basemetals/data/RailRecipeAdvancementTest.java new file mode 100644 index 00000000..6610c76c --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/data/RailRecipeAdvancementTest.java @@ -0,0 +1,78 @@ +package com.mcmoddev.basemetals.data; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.io.Reader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +class RailRecipeAdvancementTest { + + private static final Path ADVANCEMENT = Paths.get( + "src", "main", "resources", "assets", "basemetals", "advancements", + "recipes", "transportation", "rail.json"); + + @Test + void ironOrSteelUnlocksBothRailRecipes() throws IOException { + assertTrue(Files.isRegularFile(ADVANCEMENT), + "Missing recipe-book advancement " + ADVANCEMENT); + + final JsonObject advancement = read(ADVANCEMENT); + assertEquals("minecraft:recipes/root", advancement.get("parent").getAsString()); + assertEquals(setOf("minecraft:rail", "basemetals:rail"), + strings(advancement.getAsJsonObject("rewards").getAsJsonArray("recipes"))); + + final JsonObject criteria = advancement.getAsJsonObject("criteria"); + assertInventoryCriterion(criteria.getAsJsonObject("has_iron_ingot"), + "minecraft:iron_ingot"); + assertInventoryCriterion(criteria.getAsJsonObject("has_steel_ingot"), + "basemetals:steel_ingot"); + final JsonObject unlocked = criteria.getAsJsonObject("has_the_recipe"); + assertEquals("minecraft:recipe_unlocked", unlocked.get("trigger").getAsString()); + assertEquals("basemetals:rail", + unlocked.getAsJsonObject("conditions").get("recipe").getAsString()); + + final JsonArray requirements = advancement.getAsJsonArray("requirements"); + assertEquals(1, requirements.size(), "The three discovery paths must be alternatives"); + assertEquals(setOf("has_iron_ingot", "has_steel_ingot", "has_the_recipe"), + strings(requirements.get(0).getAsJsonArray())); + } + + private static void assertInventoryCriterion(final JsonObject criterion, final String item) { + assertEquals("minecraft:inventory_changed", criterion.get("trigger").getAsString()); + final JsonArray items = criterion.getAsJsonObject("conditions").getAsJsonArray("items"); + assertEquals(1, items.size()); + assertEquals(item, items.get(0).getAsJsonObject().get("item").getAsString()); + } + + private static JsonObject read(final Path path) throws IOException { + try (Reader reader = Files.newBufferedReader(path)) { + return new JsonParser().parse(reader).getAsJsonObject(); + } + } + + private static Set strings(final JsonArray values) { + final Set result = new HashSet<>(); + for (final JsonElement value : values) { + result.add(value.getAsString()); + } + return result; + } + + private static Set setOf(final String... values) { + return new HashSet<>(Arrays.asList(values)); + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/init/BlocksTests.java b/src/test/java/com/mcmoddev/basemetals/init/BlocksTests.java deleted file mode 100644 index 4ac8ff90..00000000 --- a/src/test/java/com/mcmoddev/basemetals/init/BlocksTests.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.mcmoddev.basemetals.init; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; - -class BlocksTests { - - @BeforeAll - static void setUpBeforeClass() throws Exception { - // Blocks.registerVanilla() - } - - @AfterAll - static void tearDownAfterClass() throws Exception { - } - - @BeforeEach - void setUp() throws Exception { - } - - @AfterEach - void tearDown() throws Exception { - } - - // @Test - // void testRegisterVanillaRegistersCoalBlock() { - // final MMDMaterial coal = Materials.getMaterialByName(MaterialNames.COAL) - // - // Block block = - // coal.getBlock(net.minecraft.init.Blocks.COAL_BLOCK.getRegistryName().getResourcePath()) - // - // assertNotNull(block) - // } -} diff --git a/src/test/java/com/mcmoddev/basemetals/network/ContentModeNetworkTest.java b/src/test/java/com/mcmoddev/basemetals/network/ContentModeNetworkTest.java new file mode 100644 index 00000000..256c24b9 --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/network/ContentModeNetworkTest.java @@ -0,0 +1,33 @@ +package com.mcmoddev.basemetals.network; + +import com.mcmoddev.basemetals.content.ContentMode; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ContentModeNetworkTest { + @Test + void everyStableModeRoundTripsOverTheHandshake() { + for (final ContentMode mode : ContentMode.values()) { + final ByteBuf buffer = Unpooled.buffer(); + new ContentModeMessage(mode).toBytes(buffer); + final ContentModeMessage decoded = new ContentModeMessage(); + decoded.fromBytes(buffer); + assertTrue(decoded.hasValidMode()); + assertEquals(mode, decoded.mode()); + assertTrue(ContentModeNetwork.modesMatch(mode, decoded.mode())); + } + } + + @Test + void genuineModeDifferencesAreRejectedByTheComparisonContract() { + assertFalse(ContentModeNetwork.modesMatch( + ContentMode.HIGH_FANTASY, ContentMode.LOW_FANTASY)); + assertFalse(ContentModeNetwork.modesMatch( + ContentMode.LOW_FANTASY, ContentMode.REALISM)); + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsClientConfigRuntimeProbe.java b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsClientConfigRuntimeProbe.java new file mode 100644 index 00000000..c8f72296 --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsClientConfigRuntimeProbe.java @@ -0,0 +1,79 @@ +package com.mcmoddev.basemetals.test; + +import com.mcmoddev.basemetals.client.config.BaseMetalsConfigScreen; +import net.minecraft.client.gui.GuiScreen; +import net.minecraftforge.fml.client.config.GuiConfig; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventHandler; +import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import zone.moddev.mc.orespawn.api.client.WorldSettingsExtension; +import zone.moddev.mc.orespawn.api.client.WorldSettingsExtensionRegistry; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.Properties; +import java.util.stream.Collectors; + +/** Test-only client probe. This class is packaged separately and never enters the release jar. */ +@Mod( + modid = BaseMetalsClientConfigRuntimeProbe.MODID, + name = "Base Metals Client Configuration Probe", + version = "1", + clientSideOnly = true, + dependencies = "required-after:basemetals;required-after:orespawn@[4.1.0.112021,5.0.0)", + acceptedMinecraftVersions = "[1.12.2]") +public final class BaseMetalsClientConfigRuntimeProbe { + public static final String MODID = "basemetals_client_config_probe"; + + @EventHandler + public void init(final FMLInitializationEvent event) throws IOException { + final List extensions = WorldSettingsExtensionRegistry.extensions() + .stream() + .filter(extension -> "basemetals".equals(extension.id().getNamespace())) + .collect(Collectors.toList()); + require(extensions.size() == 1, "Expected exactly one Base Metals client extension"); + final WorldSettingsExtension extension = extensions.get(0); + require("basemetals:configuration".equals(extension.id().toString()), + "Unexpected extension id " + extension.id()); + require("button.orespawn.mod.configure".equals(extension.buttonTranslationKey()), + "Base Metals row does not use OreSpawn's Configure/cog action"); + + final GuiScreen parent = new GuiScreen() { }; + final GuiScreen created = extension.createScreen(parent); + require(created instanceof BaseMetalsConfigScreen, + "Extension did not create BaseMetalsConfigScreen"); + final GuiConfig screen = (GuiConfig) created; + require(screen.parentScreen == parent, "OreSpawn parent screen was not preserved"); + require(screen.configElements.size() == 5, "Expected five root categories"); + final int properties = screen.configElements.stream() + .mapToInt(element -> element.getChildElements().size()).sum(); + require(properties == 93, "Expected 93 Base Metals options, found " + properties); + + final String markerPath = System.getProperty("basemetals.clientConfigProbe.marker"); + if (markerPath != null && !markerPath.trim().isEmpty()) { + final Properties result = new Properties(); + result.setProperty("extension", extension.id().toString()); + result.setProperty("button", extension.buttonTranslationKey()); + result.setProperty("screen", created.getClass().getName()); + result.setProperty("parent", Boolean.toString(screen.parentScreen == parent)); + result.setProperty("categories", Integer.toString(screen.configElements.size())); + result.setProperty("properties", Integer.toString(properties)); + final File marker = new File(markerPath); + final File parentDirectory = marker.getParentFile(); + if (parentDirectory != null) { + parentDirectory.mkdirs(); + } + try (FileOutputStream output = new FileOutputStream(marker)) { + result.store(output, "Base Metals OreSpawn client configuration probe"); + } + } + } + + private static void require(final boolean condition, final String message) { + if (!condition) { + throw new IllegalStateException(message); + } + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsRuntimeProbe.java b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsRuntimeProbe.java index fe1e9eff..1d351caf 100644 --- a/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsRuntimeProbe.java +++ b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsRuntimeProbe.java @@ -3,11 +3,59 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Properties; +import java.util.UUID; +import com.mojang.authlib.GameProfile; +import com.mcmoddev.basemetals.data.MaterialNames; +import com.mcmoddev.basemetals.items.ItemBaseMetalsArrow; +import com.mcmoddev.basemetals.items.ItemBaseMetalsBolt; +import com.mcmoddev.basemetals.items.ItemBaseMetalsBow; +import com.mcmoddev.basemetals.items.ItemBaseMetalsCrossbow; +import com.mcmoddev.basemetals.properties.ColdIronProperty; +import com.mcmoddev.basemetals.properties.StarSteelProperty; +import com.mcmoddev.lib.data.Names; +import com.mcmoddev.lib.entity.EntityCustomArrow; +import com.mcmoddev.lib.entity.EntityCustomBolt; +import com.mcmoddev.lib.entity.EntityHelpers; +import com.mcmoddev.lib.init.Materials; +import com.mcmoddev.lib.item.ItemBolt; +import com.mcmoddev.lib.material.MMDMaterial; + +import net.minecraft.advancements.Advancement; import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.monster.EntityIronGolem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.projectile.EntityArrow; +import net.minecraft.init.Enchantments; +import net.minecraft.init.Blocks; +import net.minecraft.init.MobEffects; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.inventory.InventoryCrafting; import net.minecraft.item.Item; +import net.minecraft.item.Item.ToolMaterial; +import net.minecraft.item.ItemArrow; +import net.minecraft.item.ItemHoe; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.potion.PotionEffect; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.management.PlayerInteractionManager; +import net.minecraft.tileentity.TileEntityFurnace; +import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Mod; @@ -20,6 +68,7 @@ modid = BaseMetalsRuntimeProbe.MODID, name = "Base Metals Runtime Probe", version = "1", + dependencies = "required-after:basemetals", acceptedMinecraftVersions = "[1.12.2]") public final class BaseMetalsRuntimeProbe { public static final String MODID = "basemetals_runtime_probe"; @@ -27,23 +76,61 @@ public final class BaseMetalsRuntimeProbe { @EventHandler public void serverStarted(final FMLServerStartedEvent event) throws IOException { final String expectedOreSpawn = requiredProperty("basemetals.probe.expectedOrespawn"); + final boolean expectedAncientWarfare = Boolean.parseBoolean( + System.getProperty("basemetals.probe.expectedAncientWarfare", "false")); + final boolean expectedCoFHWorld = Boolean.parseBoolean( + System.getProperty("basemetals.probe.expectedCoFHWorld", "false")); final File marker = new File(requiredProperty("basemetals.probe.marker")); final Properties result = new Properties(); require(Loader.isModLoaded("basemetals"), "Base Metals did not load"); require(Loader.isModLoaded("mmdlib"), "MMDLib did not load"); require(Loader.isModLoaded("orespawn"), "OreSpawn did not load"); + require(Loader.isModLoaded("ancientwarfare") == expectedAncientWarfare, + "Ancient Warfare presence did not match the requested compatibility profile"); + require(Loader.isModLoaded("ancientwarfarenpc") == expectedAncientWarfare, + "Ancient Warfare NPC presence did not match the requested compatibility profile"); + require(Loader.isModLoaded("cofhworld") == expectedCoFHWorld, + "CoFH World presence did not match the requested compatibility profile"); requireRegistered(Block.REGISTRY.getObject(new ResourceLocation("basemetals", "copper_ore")), "basemetals:copper_ore"); requireRegistered(Block.REGISTRY.getObject(new ResourceLocation("basemetals", "adamantine_ore")), "basemetals:adamantine_ore"); requireRegistered(Item.REGISTRY.getObject(new ResourceLocation("basemetals", "steel_ingot")), "basemetals:steel_ingot"); + final int fuelFormsChecked = verifyFuelForms(); + final int fishingRodsChecked = verifyFishingRodDurability(); + final int hoeMaterialNamesChecked = verifyHoeMaterialNames(); + final int ancientWarfareHoeChecks = expectedAncientWarfare + ? verifyAncientWarfareHoes( + FMLCommonHandler.instance().getMinecraftServerInstance().getEntityWorld()) + : 0; + final int doorRecipesChecked = verifyDoorAndTrapdoorRecipes( + FMLCommonHandler.instance().getMinecraftServerInstance().getEntityWorld()); + final int railRecipesChecked = verifyRailRecipes( + FMLCommonHandler.instance().getMinecraftServerInstance().getEntityWorld()); + final int railRecipeAdvancementsChecked = verifyRailRecipeAdvancement( + FMLCommonHandler.instance().getMinecraftServerInstance()); + final int crossbowBoltsChecked = verifyCrossbowBoltImpact( + FMLCommonHandler.instance().getMinecraftServerInstance()); + final int bowArrowsChecked = verifyBowArrowImpact( + FMLCommonHandler.instance().getMinecraftServerInstance()); + final int arrowPickupIdentitiesChecked = verifyArrowPickupIdentity( + FMLCommonHandler.instance().getMinecraftServerInstance()); + final int crossbowsChecked = verifyCrossbowRegistrations(); + final int rangedItemsChecked = verifyRangedItemRegistrations(); + final int rangedDamageChecks = verifyRangedDamage( + FMLCommonHandler.instance().getMinecraftServerInstance()); + final int armorEffectChecks = verifyArmorEffects( + FMLCommonHandler.instance().getMinecraftServerInstance()); + final WorldgenCounts worldgen = expectedCoFHWorld + ? verifyCoFHWorldgen(FMLCommonHandler.instance().getMinecraftServerInstance()) + : new WorldgenCounts(0, 0); final String baseMetalsVersion = version("basemetals"); final String mmdLibVersion = version("mmdlib"); final String oreSpawnVersion = version("orespawn"); - require("2.5.1.112021".equals(baseMetalsVersion), + require("2.6.0.112021".equals(baseMetalsVersion), "Unexpected Base Metals version " + baseMetalsVersion); // The artifact build is rc2.36, while its public FML metadata retains // the upstream mod version rc2. @@ -56,6 +143,25 @@ public void serverStarted(final FMLServerStartedEvent event) throws IOException result.setProperty("mmdlib", mmdLibVersion); result.setProperty("orespawn", oreSpawnVersion); result.setProperty("phase", System.getProperty("basemetals.probe.phase", "unknown")); + result.setProperty("fuelFormsChecked", Integer.toString(fuelFormsChecked)); + result.setProperty("fishingRodsChecked", Integer.toString(fishingRodsChecked)); + result.setProperty("hoeMaterialNamesChecked", Integer.toString(hoeMaterialNamesChecked)); + result.setProperty("ancientWarfare", Boolean.toString(expectedAncientWarfare)); + result.setProperty("cofhWorld", Boolean.toString(expectedCoFHWorld)); + result.setProperty("managedOres", Integer.toString(worldgen.managedOres)); + result.setProperty("cofhAntimony", Integer.toString(worldgen.cofhAntimony)); + result.setProperty("ancientWarfareHoeChecks", Integer.toString(ancientWarfareHoeChecks)); + result.setProperty("doorRecipesChecked", Integer.toString(doorRecipesChecked)); + result.setProperty("railRecipesChecked", Integer.toString(railRecipesChecked)); + result.setProperty("railRecipeAdvancementsChecked", Integer.toString(railRecipeAdvancementsChecked)); + result.setProperty("crossbowBoltsChecked", Integer.toString(crossbowBoltsChecked)); + result.setProperty("bowArrowsChecked", Integer.toString(bowArrowsChecked)); + result.setProperty("arrowPickupIdentitiesChecked", + Integer.toString(arrowPickupIdentitiesChecked)); + result.setProperty("crossbowsChecked", Integer.toString(crossbowsChecked)); + result.setProperty("rangedItemsChecked", Integer.toString(rangedItemsChecked)); + result.setProperty("rangedDamageChecks", Integer.toString(rangedDamageChecks)); + result.setProperty("armorEffectChecks", Integer.toString(armorEffectChecks)); result.setProperty("registered", "true"); marker.getParentFile().mkdirs(); try (FileOutputStream output = new FileOutputStream(marker)) { @@ -64,6 +170,1139 @@ public void serverStarted(final FMLServerStartedEvent event) throws IOException FMLCommonHandler.instance().getMinecraftServerInstance().initiateShutdown(); } + private static WorldgenCounts verifyCoFHWorldgen(final MinecraftServer server) { + final WorldServer world = server.getWorld(0); + final BlockPos spawn = world.getSpawnPoint(); + final int centerX = spawn.getX() >> 4; + final int centerZ = spawn.getZ() >> 4; + + // Load a one-chunk border so Forge population runs for every chunk in + // the bounded 9x9 sample at the centre. + for (int chunkX = centerX - 5; chunkX <= centerX + 5; chunkX++) { + for (int chunkZ = centerZ - 5; chunkZ <= centerZ + 5; chunkZ++) { + world.getChunkProvider().provideChunk(chunkX, chunkZ); + } + } + + final Block antimony = Block.REGISTRY.getObject( + new ResourceLocation("basemetals", "antimony_ore")); + int managedOres = 0; + int cofhAntimony = 0; + for (int chunkX = centerX - 4; chunkX <= centerX + 4; chunkX++) { + for (int chunkZ = centerZ - 4; chunkZ <= centerZ + 4; chunkZ++) { + final Chunk chunk = world.getChunkProvider().provideChunk(chunkX, chunkZ); + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + for (int y = 0; y < 128; y++) { + final Block block = chunk.getBlockState( + new BlockPos(x, y, z)).getBlock(); + if (block == antimony) { + cofhAntimony++; + } else if (isManagedBaseMetalsOre(block)) { + managedOres++; + } + } + } + } + } + } + require(managedOres == 0, + "Disabled OreSpawn provider placed " + managedOres + " managed Base Metals ores"); + require(cofhAntimony > 0, + "CoFH World did not place the Base Metals antimony test ore"); + return new WorldgenCounts(managedOres, cofhAntimony); + } + + private static boolean isManagedBaseMetalsOre(final Block block) { + final ResourceLocation name = block.getRegistryName(); + if (name == null || !"basemetals".equals(name.getNamespace())) { + return false; + } + switch (name.getPath()) { + case "coldiron_ore": + case "adamantine_ore": + case "starsteel_ore": + case "copper_ore": + case "silver_ore": + case "tin_ore": + case "lead_ore": + case "zinc_ore": + case "mercury_ore": + case "nickel_ore": + case "platinum_ore": + return true; + default: + return false; + } + } + + private static final class WorldgenCounts { + private final int managedOres; + private final int cofhAntimony; + + private WorldgenCounts(final int managedOres, final int cofhAntimony) { + this.managedOres = managedOres; + this.cofhAntimony = cofhAntimony; + } + } + + private static int verifyFuelForms() { + int checked = 0; + for (final Item item : Item.REGISTRY) { + final ResourceLocation registryName = item.getRegistryName(); + if (registryName == null || !"basemetals".equals(registryName.getNamespace())) { + continue; + } + + final String path = registryName.getPath(); + if (!isNuggetOrPowder(path)) { + continue; + } + + final int expected = expectedBurnTime(path); + final int actual = TileEntityFurnace.getItemBurnTime(new ItemStack(item)); + require(actual == expected, + registryName + " has furnace burn time " + actual + ", expected " + expected); + checked++; + } + require(checked > 0, "No Base Metals nugget or powder fuel forms were checked"); + return checked; + } + + private static int verifyFishingRodDurability() { + int checked = 0; + for (final MMDMaterial material : Materials.getAllMaterials()) { + if (!material.hasItem(Names.FISHING_ROD)) { + continue; + } + + final Item fishingRod = material.getItem(Names.FISHING_ROD); + final ResourceLocation registryName = fishingRod.getRegistryName(); + if (registryName == null || !"basemetals".equals(registryName.getNamespace())) { + continue; + } + + final int expected = material.getToolDurability(); + final int actual = new ItemStack(fishingRod).getMaxDamage(); + require(actual == expected, + registryName + " has maximum durability " + actual + ", expected " + expected); + checked++; + } + require(checked == 27, + "Checked " + checked + " Base Metals fishing rods, expected 27"); + return checked; + } + + private static int verifyHoeMaterialNames() { + int checked = 0; + for (final MMDMaterial material : Materials.getAllMaterials()) { + if (!material.hasItem(Names.HOE)) { + continue; + } + + final Item hoe = material.getItem(Names.HOE); + final ResourceLocation registryName = hoe.getRegistryName(); + if (registryName == null || !"basemetals".equals(registryName.getNamespace())) { + continue; + } + + require(hoe instanceof ItemHoe, + registryName + " is not an ItemHoe"); + final String materialName = ((ItemHoe) hoe).getMaterialName(); + final ToolMaterial resolved; + try { + resolved = ToolMaterial.valueOf(materialName); + } catch (final IllegalArgumentException exception) { + throw new IllegalStateException(registryName + " exposes invalid ToolMaterial name " + + materialName, exception); + } + final ToolMaterial expected = Materials.getToolMaterialFor(material); + require(resolved == expected, + registryName + " exposes ToolMaterial " + resolved + + ", expected " + expected); + checked++; + } + require(checked == 24, + "Checked " + checked + " Base Metals hoe material names, expected 24"); + return checked; + } + + private static int verifyAncientWarfareHoes(final World world) { + try { + final Class workerClass = Class.forName( + "net.shadowmage.ancientwarfare.npc.entity.NpcWorker"); + final Class workTypeClass = Class.forName( + "net.shadowmage.ancientwarfare.core.interfaces.IWorkSite$WorkType"); + final Object farming = enumConstant(workTypeClass, "FARMING"); + final Method effectivenessMethod = workerClass.getMethod( + "getWorkEffectiveness", workTypeClass); + int checked = 0; + for (final String path : new String[] { + "emerald_hoe", "steel_hoe", "adamantine_hoe" }) { + final EntityLivingBase worker = (EntityLivingBase) workerClass + .getConstructor(World.class).newInstance(world); + worker.setHeldItem(EnumHand.MAIN_HAND, + new ItemStack(requireItem("basemetals", path))); + final float effectiveness = ((Number) effectivenessMethod + .invoke(worker, farming)).floatValue(); + require(!Float.isNaN(effectiveness) && !Float.isInfinite(effectiveness) + && effectiveness > 0.0F, + "Ancient Warfare returned invalid work effectiveness " + + effectiveness + " for basemetals:" + path); + checked++; + } + require(checked == 3, + "Checked " + checked + " Ancient Warfare hoes, expected 3"); + return checked; + } catch (final InvocationTargetException exception) { + throw new IllegalStateException("Ancient Warfare rejected a Base Metals hoe", + exception.getCause()); + } catch (final ReflectiveOperationException exception) { + throw new IllegalStateException( + "Could not exercise Ancient Warfare's farming effectiveness path", exception); + } + } + + private static Object enumConstant(final Class enumClass, final String name) { + for (final Object constant : enumClass.getEnumConstants()) { + if (((Enum) constant).name().equals(name)) { + return constant; + } + } + throw new IllegalStateException("Missing enum constant " + enumClass.getName() + "." + name); + } + + private static boolean isNuggetOrPowder(final String path) { + return path.endsWith("_nugget") + || path.endsWith("_powder") + || path.endsWith("_smallpowder"); + } + + private static int expectedBurnTime(final String path) { + if (path.startsWith("coal_") || path.startsWith("charcoal_")) { + return path.endsWith("_powder") ? 1600 : 200; + } + return 0; + } + + private static int verifyDoorAndTrapdoorRecipes(final World world) { + int checked = 0; + checked += verifyDoorAndTrapdoorRecipe(world, net.minecraft.init.Items.DIAMOND, "diamond"); + checked += verifyDoorAndTrapdoorRecipe(world, net.minecraft.init.Items.EMERALD, "emerald"); + checked += verifyDoorAndTrapdoorRecipe(world, net.minecraft.init.Items.GOLD_INGOT, "gold"); + checked += verifyDoorAndTrapdoorRecipe(world, net.minecraft.init.Items.QUARTZ, "quartz"); + return checked; + } + + private static int verifyRailRecipes(final World world) { + final Item steel = requireItem("basemetals", "steel_ingot"); + final Item stick = net.minecraft.init.Items.STICK; + final Item redstone = net.minecraft.init.Items.REDSTONE; + final Item redstoneTorch = Item.getItemFromBlock(Blocks.REDSTONE_TORCH); + final Item stonePressurePlate = Item.getItemFromBlock(Blocks.STONE_PRESSURE_PLATE); + + verifyRailRecipe(world, "rail", Item.getItemFromBlock(Blocks.RAIL), 16, + steel, null, steel, + steel, stick, steel, + steel, null, steel); + verifyRailRecipe(world, "activator_rail", Item.getItemFromBlock(Blocks.ACTIVATOR_RAIL), 6, + steel, stick, steel, + steel, redstoneTorch, steel, + steel, stick, steel); + verifyRailRecipe(world, "detector_rail", Item.getItemFromBlock(Blocks.DETECTOR_RAIL), 6, + steel, null, steel, + steel, stonePressurePlate, steel, + steel, redstone, steel); + return 3; + } + + private static int verifyRailRecipeAdvancement(final MinecraftServer server) { + final ResourceLocation advancementId = new ResourceLocation( + "basemetals", "recipes/transportation/rail"); + final Advancement advancement = server.getAdvancementManager().getAdvancement(advancementId); + require(advancement != null, "Recipe-book advancement was not loaded: " + advancementId); + require(advancement.getCriteria().containsKey("has_iron_ingot"), + advancementId + " does not recognize iron ingots"); + require(advancement.getCriteria().containsKey("has_steel_ingot"), + advancementId + " does not recognize Base Metals steel ingots"); + require(advancement.getCriteria().containsKey("has_the_recipe"), + advancementId + " lacks its recipe-unlocked criterion"); + require(advancement.getRequirements().length == 1 + && advancement.getRequirements()[0].length == 3, + advancementId + " discovery criteria are not alternatives"); + return 1; + } + + private static int verifyCrossbowBoltImpact(final MinecraftServer server) { + final WorldServer world = server.getWorld(0); + final Item crossbow = requireItem("basemetals", "steel_crossbow"); + final Item boltItem = requireItem("basemetals", "steel_bolt"); + final ItemStack crossbowStack = new ItemStack(crossbow); + final ItemStack ammunition = new ItemStack(boltItem); + final EntityPlayerMP shooter = new EntityPlayerMP(server, world, + new GameProfile(UUID.randomUUID(), "BaseMetalsBoltProbe"), + new PlayerInteractionManager(world)); + final BlockPos spawn = world.getSpawnPoint(); + final double x = spawn.getX() + 0.5D; + final double y = spawn.getY() + 16.0D; + final double z = spawn.getZ() + 0.5D; + shooter.setPositionAndRotation(x, y, z, 0.0F, 0.0F); + shooter.setHeldItem(EnumHand.OFF_HAND, ammunition); + + final EntityIronGolem target = new EntityIronGolem(world); + target.setPosition(x, y, z + 2.5D); + require(world.spawnEntity(target), "Could not spawn the crossbow impact target"); + final float healthBefore = target.getHealth(); + final int boltsBefore = countBolts(world); + EntityCustomBolt projectile = null; + try { + crossbow.onPlayerStoppedUsing(crossbowStack, world, shooter, + crossbow.getMaxItemUseDuration(crossbowStack) - 20); + require(countBolts(world) == boltsBefore + 1, + "Base Metals crossbow did not create a server-side bolt"); + projectile = findLiveBolt(world); + require(projectile != null, "Spawned Base Metals bolt could not be located"); + final MMDMaterial steel = Materials.getMaterialByName(MaterialNames.STEEL); + requireDamage(steel.getBaseAttackDamage() * 2.0D, projectile.getDamage(), + "steel crossbow and bolt impact projectile"); + final ItemStack savedAmmunition = EntityHelpers.readFromNBTItemStack( + projectile.writeToNBT(new NBTTagCompound())); + require(savedAmmunition.getItem() == boltItem && savedAmmunition.getCount() == 1, + "Base Metals bolt did not preserve its ammunition item"); + for (int tick = 0; tick < 4 && target.getHealth() == healthBefore; tick++) { + projectile.onUpdate(); + } + require(target.getHealth() < healthBefore, + "Base Metals crossbow bolt did not damage its target"); + require(ammunition.isEmpty(), + "Base Metals crossbow consumed an unexpected number of bolts"); + require(crossbowStack.getItemDamage() == 1, + "Base Metals crossbow did not lose one durability after firing"); + } finally { + if (projectile != null) { + projectile.setDead(); + } + target.setDead(); + } + return 1; + } + + private static int verifyBowArrowImpact(final MinecraftServer server) { + final WorldServer world = server.getWorld(0); + final Item bow = requireItem("basemetals", "steel_bow"); + final Item arrowItem = requireItem("basemetals", "steel_arrow"); + final ItemStack bowStack = new ItemStack(bow); + final ItemStack ammunition = new ItemStack(arrowItem); + final EntityPlayerMP shooter = new EntityPlayerMP(server, world, + new GameProfile(UUID.randomUUID(), "BaseMetalsArrowProbe"), + new PlayerInteractionManager(world)); + final BlockPos spawn = world.getSpawnPoint(); + final double x = spawn.getX() + 0.5D; + final double y = spawn.getY() + 16.0D; + final double z = spawn.getZ() + 0.5D; + shooter.setPositionAndRotation(x, y, z, 0.0F, 0.0F); + shooter.setHeldItem(EnumHand.OFF_HAND, ammunition); + + final EntityIronGolem target = new EntityIronGolem(world); + target.setPosition(x, y, z + 2.5D); + require(world.spawnEntity(target), "Could not spawn the bow impact target"); + final float healthBefore = target.getHealth(); + final int arrowsBefore = countArrows(world); + EntityArrow projectile = null; + try { + bow.onPlayerStoppedUsing(bowStack, world, shooter, + bow.getMaxItemUseDuration(bowStack) - 20); + require(countArrows(world) == arrowsBefore + 1, + "Base Metals bow did not create a server-side arrow"); + projectile = findLiveArrow(world); + require(projectile != null, "Spawned Base Metals arrow could not be located"); + final MMDMaterial steel = Materials.getMaterialByName(MaterialNames.STEEL); + requireDamage(steel.getBaseAttackDamage() * 2.0D, projectile.getDamage(), + "steel bow and arrow impact projectile"); + final ItemStack savedAmmunition = EntityHelpers.readFromNBTItemStack( + projectile.writeToNBT(new NBTTagCompound())); + require(savedAmmunition.getItem() == arrowItem && savedAmmunition.getCount() == 1, + "Base Metals arrow did not preserve its ammunition item"); + for (int tick = 0; tick < 4 && target.getHealth() == healthBefore; tick++) { + projectile.onUpdate(); + } + require(target.getHealth() < healthBefore, + "Base Metals bow arrow did not damage its target"); + require(ammunition.isEmpty(), + "Base Metals bow consumed an unexpected number of arrows"); + require(bowStack.getItemDamage() == 1, + "Base Metals bow did not lose one durability after firing"); + } finally { + if (projectile != null) { + projectile.setDead(); + } + target.setDead(); + } + return 1; + } + + private static int verifyArrowPickupIdentity(final MinecraftServer server) { + final WorldServer world = server.getWorld(0); + final EntityPlayerMP shooter = new EntityPlayerMP(server, world, + new GameProfile(UUID.randomUUID(), "BaseMetalsArrowIdentityProbe"), + new PlayerInteractionManager(world)); + final BlockPos spawn = world.getSpawnPoint(); + shooter.setPositionAndRotation(spawn.getX() + 0.5D, spawn.getY() + 16.0D, + spawn.getZ() + 0.5D, 0.0F, 0.0F); + + int checked = 0; + for (final MMDMaterial material : Materials.getAllMaterials()) { + if (!isBaseMetalsItem(material, Names.ARROW)) { + continue; + } + final Item arrowItem = material.getItem(Names.ARROW); + final ItemStack inventoryAmmunition = new ItemStack(arrowItem); + final EntityCustomArrow projectile = ((ItemBaseMetalsArrow) arrowItem) + .createArrow(world, inventoryAmmunition, shooter); + inventoryAmmunition.shrink(1); + require(inventoryAmmunition.isEmpty(), + arrowItem.getRegistryName() + " identity test did not consume its source stack"); + + final NBTTagCompound saved = projectile.writeToNBT(new NBTTagCompound()); + final ItemStack pickup = EntityHelpers.readFromNBTItemStack(saved); + require(pickup.getItem() == arrowItem && pickup.getCount() == 1, + arrowItem.getRegistryName() + " became another item before pickup"); + + final EntityCustomArrow reloaded = new EntityCustomArrow(world); + reloaded.readFromNBT(saved); + final ItemStack reloadedPickup = EntityHelpers.readFromNBTItemStack( + reloaded.writeToNBT(new NBTTagCompound())); + require(reloadedPickup.getItem() == arrowItem && reloadedPickup.getCount() == 1, + arrowItem.getRegistryName() + " lost its identity after save and reload"); + projectile.setDead(); + reloaded.setDead(); + checked++; + } + require(checked == 27, + "Checked " + checked + " Base Metals arrow identities, expected 27"); + + final Item arrowItem = requireItem("basemetals", "steel_arrow"); + final ItemStack ammunition = new ItemStack(arrowItem); + final ItemStack vanillaBow = new ItemStack(net.minecraft.init.Items.BOW); + shooter.setHeldItem(EnumHand.OFF_HAND, ammunition); + final int arrowsBefore = countArrows(world); + EntityArrow projectile = null; + try { + net.minecraft.init.Items.BOW.onPlayerStoppedUsing(vanillaBow, world, shooter, + vanillaBow.getMaxItemUseDuration() - 20); + require(countArrows(world) == arrowsBefore + 1, + "Vanilla bow did not create a Base Metals arrow projectile"); + projectile = findLiveArrow(world); + require(projectile instanceof EntityCustomArrow, + "Vanilla bow did not retain the Base Metals arrow entity"); + require(ammunition.isEmpty(), + "Vanilla bow did not consume the last Base Metals arrow"); + final ItemStack pickup = EntityHelpers.readFromNBTItemStack( + projectile.writeToNBT(new NBTTagCompound())); + require(pickup.getItem() == arrowItem && pickup.getCount() == 1, + "Vanilla bow changed a Base Metals arrow into another pickup item"); + } finally { + if (projectile != null) { + projectile.setDead(); + } + } + return checked + 1; + } + + private static int verifyCrossbowRegistrations() { + int checked = 0; + for (final MMDMaterial material : Materials.getAllMaterials()) { + if (!material.hasItem(Names.CROSSBOW)) { + continue; + } + final Item crossbow = material.getItem(Names.CROSSBOW); + final ResourceLocation registryName = crossbow.getRegistryName(); + if (registryName == null || !"basemetals".equals(registryName.getNamespace())) { + continue; + } + require(crossbow instanceof ItemBaseMetalsCrossbow, + registryName + " does not use the corrected Base Metals crossbow implementation"); + checked++; + } + require(checked == 27, "Checked " + checked + " Base Metals crossbows, expected 27"); + return checked; + } + + private static int verifyRangedItemRegistrations() { + int arrows = 0; + int bolts = 0; + int bows = 0; + for (final MMDMaterial material : Materials.getAllMaterials()) { + if (isBaseMetalsItem(material, Names.ARROW)) { + require(material.getItem(Names.ARROW) instanceof ItemBaseMetalsArrow, + material.getItem(Names.ARROW).getRegistryName() + + " does not use the material-damage arrow implementation"); + arrows++; + } + if (isBaseMetalsItem(material, Names.BOLT)) { + require(material.getItem(Names.BOLT) instanceof ItemBaseMetalsBolt, + material.getItem(Names.BOLT).getRegistryName() + + " does not use the material-damage bolt implementation"); + bolts++; + } + if (isBaseMetalsItem(material, Names.BOW)) { + require(material.getItem(Names.BOW) instanceof ItemBaseMetalsBow, + material.getItem(Names.BOW).getRegistryName() + + " does not use the material-damage bow implementation"); + bows++; + } + } + require(arrows == 27, "Checked " + arrows + " Base Metals arrows, expected 27"); + require(bolts == 27, "Checked " + bolts + " Base Metals bolts, expected 27"); + require(bows == 27, "Checked " + bows + " Base Metals bows, expected 27"); + return arrows + bolts + bows; + } + + private static boolean isBaseMetalsItem(final MMDMaterial material, final Names name) { + if (!material.hasItem(name)) { + return false; + } + final ResourceLocation registryName = material.getItem(name).getRegistryName(); + return registryName != null && "basemetals".equals(registryName.getNamespace()); + } + + private static int verifyRangedDamage(final MinecraftServer server) { + final WorldServer world = server.getWorld(0); + final EntityPlayerMP shooter = new EntityPlayerMP(server, world, + new GameProfile(UUID.randomUUID(), "BaseMetalsDamageProbe"), + new PlayerInteractionManager(world)); + final BlockPos spawn = world.getSpawnPoint(); + shooter.setPositionAndRotation(spawn.getX() + 0.5D, spawn.getY() + 16.0D, + spawn.getZ() + 0.5D, 0.0F, 0.0F); + int checked = 0; + + for (final MMDMaterial material : Materials.getAllMaterials()) { + if (!isBaseMetalsItem(material, Names.ARROW) + || !isBaseMetalsItem(material, Names.BOLT) + || !isBaseMetalsItem(material, Names.BOW) + || !isBaseMetalsItem(material, Names.CROSSBOW)) { + continue; + } + final double component = material.getBaseAttackDamage(); + requireDamage(1.0D + component, createArrowDamage(world, shooter, material), + material.getName() + " arrow ammunition"); + requireDamage(1.0D + component, createBoltDamage(world, shooter, material), + material.getName() + " bolt ammunition"); + requireDamage(component + component, + fireBowDamage(world, shooter, material.getItem(Names.BOW), + material.getItem(Names.ARROW), 0), + material.getName() + " matching bow and arrow"); + requireDamage(component + component, + fireCrossbowDamage(world, shooter, material.getItem(Names.CROSSBOW), + material.getItem(Names.BOLT), 0), + material.getName() + " matching crossbow and bolt"); + checked += 4; + } + require(checked == 108, "Checked " + checked + " ranged material combinations, expected 108"); + + final MMDMaterial gold = Materials.getMaterialByName(MaterialNames.GOLD); + final MMDMaterial iron = Materials.getMaterialByName(MaterialNames.IRON); + final MMDMaterial adamantine = Materials.getMaterialByName(MaterialNames.ADAMANTINE); + final MMDMaterial steel = Materials.getMaterialByName(MaterialNames.STEEL); + require(createArrowDamage(world, shooter, gold) + < createArrowDamage(world, shooter, iron) + && createArrowDamage(world, shooter, iron) + < createArrowDamage(world, shooter, adamantine), + "Gold, iron, and Adamantine arrows do not have increasing material damage"); + require(createBoltDamage(world, shooter, gold) + < createBoltDamage(world, shooter, iron) + && createBoltDamage(world, shooter, iron) + < createBoltDamage(world, shooter, adamantine), + "Gold, iron, and Adamantine bolts do not have increasing material damage"); + + requireDamage(2.0D, + fireBowDamage(world, shooter, net.minecraft.init.Items.BOW, + net.minecraft.init.Items.ARROW, 0), + "vanilla bow and arrow"); + checked++; + requireDamage(1.0D + adamantine.getBaseAttackDamage(), + fireBowDamage(world, shooter, net.minecraft.init.Items.BOW, + adamantine.getItem(Names.ARROW), 0), + "vanilla bow and Adamantine arrow"); + checked++; + requireDamage(1.0D + adamantine.getBaseAttackDamage(), + fireBowDamage(world, shooter, adamantine.getItem(Names.BOW), + net.minecraft.init.Items.ARROW, 0), + "Adamantine bow and vanilla arrow"); + checked++; + + final double goldBowAdamantineArrow = fireBowDamage(world, shooter, + gold.getItem(Names.BOW), adamantine.getItem(Names.ARROW), 0); + final double adamantineBowGoldArrow = fireBowDamage(world, shooter, + adamantine.getItem(Names.BOW), gold.getItem(Names.ARROW), 0); + requireDamage(gold.getBaseAttackDamage() + adamantine.getBaseAttackDamage(), + goldBowAdamantineArrow, "gold bow and Adamantine arrow"); + requireDamage(goldBowAdamantineArrow, adamantineBowGoldArrow, + "swapped bow and arrow materials"); + checked += 2; + + final double goldCrossbowAdamantineBolt = fireCrossbowDamage(world, shooter, + gold.getItem(Names.CROSSBOW), adamantine.getItem(Names.BOLT), 0); + final double adamantineCrossbowGoldBolt = fireCrossbowDamage(world, shooter, + adamantine.getItem(Names.CROSSBOW), gold.getItem(Names.BOLT), 0); + requireDamage(gold.getBaseAttackDamage() + adamantine.getBaseAttackDamage(), + goldCrossbowAdamantineBolt, "gold crossbow and Adamantine bolt"); + requireDamage(goldCrossbowAdamantineBolt, adamantineCrossbowGoldBolt, + "swapped crossbow and bolt materials"); + checked += 2; + + final int powerLevel = 2; + final double powerBonus = powerLevel * 0.5D + 0.5D; + requireDamage(steel.getBaseAttackDamage() * 2.0D + powerBonus, + fireBowDamage(world, shooter, steel.getItem(Names.BOW), + steel.getItem(Names.ARROW), powerLevel), + "Power-enchanted steel bow and arrow"); + requireDamage(steel.getBaseAttackDamage() * 2.0D + powerBonus, + fireCrossbowDamage(world, shooter, steel.getItem(Names.CROSSBOW), + steel.getItem(Names.BOLT), powerLevel), + "Power-enchanted steel crossbow and bolt"); + checked += 2; + + final ItemBolt neutralBolt = new ItemBolt(); + requireDamage(1.0D + adamantine.getBaseAttackDamage(), + fireCrossbowDamage(world, shooter, adamantine.getItem(Names.CROSSBOW), + neutralBolt, 0), + "Adamantine crossbow and neutral third-party bolt"); + checked++; + + final ItemArrow thirdPartyArrow = new ItemArrow() { + @Override + public EntityArrow createArrow(final World arrowWorld, final ItemStack stack, + final net.minecraft.entity.EntityLivingBase arrowShooter) { + final EntityArrow projectile = super.createArrow(arrowWorld, stack, arrowShooter); + projectile.setDamage(4.25D); + return projectile; + } + }; + requireDamage(4.25D - 1.0D + adamantine.getBaseAttackDamage(), + fireBowDamage(world, shooter, adamantine.getItem(Names.BOW), + thirdPartyArrow, 0), + "Adamantine bow and third-party arrow"); + checked++; + require(checked == 119, "Checked " + checked + " ranged damage cases, expected 119"); + return checked; + } + + private static double fireBowDamage(final World world, final EntityPlayer shooter, + final Item bow, final Item arrow, final int powerLevel) { + final ItemStack bowStack = new ItemStack(bow); + if (powerLevel > 0) { + bowStack.addEnchantment(Enchantments.POWER, powerLevel); + } + final ItemStack ammunition = new ItemStack(arrow, 2); + shooter.setHeldItem(EnumHand.OFF_HAND, ammunition); + final int before = countArrows(world); + EntityArrow projectile = null; + try { + bow.onPlayerStoppedUsing(bowStack, world, shooter, + bow.getMaxItemUseDuration(bowStack) - 20); + require(countArrows(world) == before + 1, + bow.getRegistryName() + " did not create a server-side arrow"); + projectile = findLiveArrow(world); + require(projectile != null, "Spawned arrow could not be located"); + require(ammunition.getCount() == 1, + bow.getRegistryName() + " consumed an unexpected number of arrows"); + require(bowStack.getItemDamage() == 1, + bow.getRegistryName() + " did not lose one durability after firing"); + return projectile.getDamage(); + } finally { + if (projectile != null) { + projectile.setDead(); + } + shooter.setHeldItem(EnumHand.OFF_HAND, ItemStack.EMPTY); + } + } + + private static double fireCrossbowDamage(final World world, final EntityPlayer shooter, + final Item crossbow, final Item bolt, final int powerLevel) { + final ItemStack crossbowStack = new ItemStack(crossbow); + if (powerLevel > 0) { + crossbowStack.addEnchantment(Enchantments.POWER, powerLevel); + } + final ItemStack ammunition = new ItemStack(bolt, 2); + shooter.setHeldItem(EnumHand.OFF_HAND, ammunition); + final int before = countBolts(world); + EntityCustomBolt projectile = null; + try { + crossbow.onPlayerStoppedUsing(crossbowStack, world, shooter, + crossbow.getMaxItemUseDuration(crossbowStack) - 20); + require(countBolts(world) == before + 1, + crossbow.getRegistryName() + " did not create a server-side bolt"); + projectile = findLiveBolt(world); + require(projectile != null, "Spawned bolt could not be located"); + require(ammunition.getCount() == 1, + crossbow.getRegistryName() + " consumed an unexpected number of bolts"); + require(crossbowStack.getItemDamage() == 1, + crossbow.getRegistryName() + " did not lose one durability after firing"); + return projectile.getDamage(); + } finally { + if (projectile != null) { + projectile.setDead(); + } + shooter.setHeldItem(EnumHand.OFF_HAND, ItemStack.EMPTY); + } + } + + private static int countArrows(final World world) { + int count = 0; + for (final Entity entity : world.loadedEntityList) { + if (entity instanceof EntityArrow && !(entity instanceof EntityCustomBolt) + && !entity.isDead) { + count++; + } + } + return count; + } + + private static EntityArrow findLiveArrow(final World world) { + for (final Entity entity : world.loadedEntityList) { + if (entity instanceof EntityArrow && !(entity instanceof EntityCustomBolt) + && !entity.isDead) { + return (EntityArrow) entity; + } + } + return null; + } + + private static void requireDamage(final double expected, final double actual, + final String description) { + require(Math.abs(expected - actual) < 0.000001D, + description + " has projectile base damage " + actual + ", expected " + expected); + } + + private static double createArrowDamage(final World world, final EntityPlayer shooter, + final MMDMaterial material) { + final Item item = material.getItem(Names.ARROW); + require(item instanceof ItemArrow, + material.getName() + " arrow is not an ItemArrow"); + final EntityArrow projectile = ((ItemArrow) item).createArrow( + world, new ItemStack(item), shooter); + final double damage = projectile.getDamage(); + projectile.setDead(); + return damage; + } + + private static double createBoltDamage(final World world, final EntityPlayer shooter, + final MMDMaterial material) { + final Item item = material.getItem(Names.BOLT); + require(item instanceof ItemBolt, + material.getName() + " bolt is not an ItemBolt"); + final EntityCustomBolt projectile = ((ItemBolt) item).createBolt( + world, new ItemStack(item), shooter); + final double damage = projectile.getDamage(); + projectile.setDead(); + return damage; + } + + private static int countBolts(final World world) { + int count = 0; + for (final Entity entity : world.loadedEntityList) { + if (entity instanceof EntityCustomBolt && !entity.isDead) { + count++; + } + } + return count; + } + + private static EntityCustomBolt findLiveBolt(final World world) { + for (final Entity entity : world.loadedEntityList) { + if (entity instanceof EntityCustomBolt && !entity.isDead) { + return (EntityCustomBolt) entity; + } + } + return null; + } + + private static int verifyArmorEffects(final MinecraftServer server) { + final WorldServer world = server.getWorld(0); + int checked = 0; + + for (int pieces = 1; pieces <= 4; pieces++) { + final EntityPlayer player = armorTestPlayer(server, world, + "StarSteel" + pieces); + final ItemStack trigger = equipArmor(player, MaterialNames.STARSTEEL, pieces); + Materials.getMaterialByName(MaterialNames.STARSTEEL).applyEffect(trigger, player); + requireEffect(player, MobEffects.JUMP_BOOST, pieces - 1, + "Star-Steel " + pieces + "-piece jump boost"); + if (pieces == 1) { + requireNoEffect(player, MobEffects.SPEED, + "Star-Steel one-piece speed boost"); + } else { + requireEffect(player, MobEffects.SPEED, pieces - 2, + "Star-Steel " + pieces + "-piece speed boost"); + } + checked += 2; + } + + for (int pieces = 1; pieces <= 4; pieces++) { + final EntityPlayer player = armorTestPlayer(server, world, + "Adamantine" + pieces); + final ItemStack trigger = equipArmor(player, MaterialNames.ADAMANTINE, pieces); + Materials.getMaterialByName(MaterialNames.ADAMANTINE).applyEffect(trigger, player); + if (pieces == 1) { + requireNoEffect(player, MobEffects.RESISTANCE, + "Adamantine one-piece resistance"); + } else { + requireEffect(player, MobEffects.RESISTANCE, pieces == 4 ? 1 : 0, + "Adamantine " + pieces + "-piece resistance"); + } + checked++; + } + + for (int pieces = 1; pieces <= 4; pieces++) { + final EntityPlayer player = armorTestPlayer(server, world, + "Lead" + pieces); + final ItemStack trigger = equipArmor(player, MaterialNames.LEAD, pieces); + Materials.getMaterialByName(MaterialNames.LEAD).applyEffect(trigger, player); + if (pieces == 1) { + requireNoEffect(player, MobEffects.SLOWNESS, + "Lead one-piece slowness"); + } else { + requireEffect(player, MobEffects.SLOWNESS, pieces == 4 ? 1 : 0, + "Lead " + pieces + "-piece slowness"); + } + checked++; + } + + final EntityPlayer coldIronPartial = armorTestPlayer(server, world, + "ColdIronPartial"); + final ItemStack coldIronPartialTrigger = equipArmor( + coldIronPartial, MaterialNames.COLDIRON, 3); + Materials.getMaterialByName(MaterialNames.COLDIRON) + .applyEffect(coldIronPartialTrigger, coldIronPartial); + requireNoEffect(coldIronPartial, MobEffects.FIRE_RESISTANCE, + "Cold-Iron partial-suit fire resistance"); + checked++; + + final EntityPlayer coldIronFull = armorTestPlayer(server, world, + "ColdIronFull"); + final ItemStack coldIronFullTrigger = equipArmor( + coldIronFull, MaterialNames.COLDIRON, 4); + Materials.getMaterialByName(MaterialNames.COLDIRON) + .applyEffect(coldIronFullTrigger, coldIronFull); + requireEffect(coldIronFull, MobEffects.FIRE_RESISTANCE, 0, + "Cold-Iron full-suit fire resistance"); + checked++; + + final EntityPlayer mithrilPartial = armorTestPlayer(server, world, + "MithrilPartial"); + final ItemStack mithrilPartialTrigger = equipArmor( + mithrilPartial, MaterialNames.MITHRIL, 3); + mithrilPartial.addPotionEffect(new PotionEffect(MobEffects.POISON, 200, 0)); + Materials.getMaterialByName(MaterialNames.MITHRIL) + .applyEffect(mithrilPartialTrigger, mithrilPartial); + requireEffect(mithrilPartial, MobEffects.POISON, 0, + "Mithril partial-suit harmful-effect preservation"); + checked++; + + final EntityPlayer mithrilFull = armorTestPlayer(server, world, + "MithrilFull"); + final ItemStack mithrilFullTrigger = equipArmor( + mithrilFull, MaterialNames.MITHRIL, 4); + mithrilFull.addPotionEffect(new PotionEffect(MobEffects.POISON, 200, 0)); + Materials.getMaterialByName(MaterialNames.MITHRIL) + .applyEffect(mithrilFullTrigger, mithrilFull); + requireNoEffect(mithrilFull, MobEffects.POISON, + "Mithril full-suit harmful-effect removal"); + checked++; + + final BlockPos waterFeet = new BlockPos(24, 80, 24); + final BlockPos waterHead = waterFeet.up(); + final net.minecraft.block.state.IBlockState originalFeet = world.getBlockState(waterFeet); + final net.minecraft.block.state.IBlockState originalHead = world.getBlockState(waterHead); + try { + world.setBlockState(waterFeet, Blocks.FLOWING_WATER.getDefaultState(), 2); + world.setBlockState(waterHead, Blocks.FLOWING_WATER.getDefaultState(), 2); + + final EntityPlayer aquariumPartial = armorTestPlayer(server, world, + "AquariumPartial"); + aquariumPartial.setPosition(24.5D, 80.0D, 24.5D); + aquariumPartial.handleWaterMovement(); + final ItemStack aquariumPartialTrigger = equipArmor( + aquariumPartial, MaterialNames.AQUARIUM, 3); + Materials.getMaterialByName(MaterialNames.AQUARIUM) + .applyEffect(aquariumPartialTrigger, aquariumPartial); + requireNoEffect(aquariumPartial, MobEffects.WATER_BREATHING, + "Aquarium partial-suit water breathing"); + checked++; + + final EntityPlayer aquariumFull = armorTestPlayer(server, world, + "AquariumFull"); + aquariumFull.setPosition(24.5D, 80.0D, 24.5D); + aquariumFull.handleWaterMovement(); + final ItemStack aquariumFullTrigger = equipArmor( + aquariumFull, MaterialNames.AQUARIUM, 4); + aquariumFull.addPotionEffect(new PotionEffect(MobEffects.MINING_FATIGUE, 200, 0)); + Materials.getMaterialByName(MaterialNames.AQUARIUM) + .applyEffect(aquariumFullTrigger, aquariumFull); + requireEffect(aquariumFull, MobEffects.WATER_BREATHING, 0, + "Aquarium full-suit water breathing"); + requireEffect(aquariumFull, MobEffects.RESISTANCE, 0, + "Aquarium full-suit resistance"); + requireNoEffect(aquariumFull, MobEffects.MINING_FATIGUE, + "Aquarium full-suit mining-fatigue removal"); + checked += 3; + } finally { + world.setBlockState(waterFeet, originalFeet, 2); + world.setBlockState(waterHead, originalHead, 2); + } + + final EntityPlayer aquariumDry = armorTestPlayer(server, world, + "AquariumDry"); + aquariumDry.setPosition(24.5D, 82.0D, 24.5D); + final ItemStack aquariumDryTrigger = equipArmor( + aquariumDry, MaterialNames.AQUARIUM, 4); + Materials.getMaterialByName(MaterialNames.AQUARIUM) + .applyEffect(aquariumDryTrigger, aquariumDry); + requireNoEffect(aquariumDry, MobEffects.WATER_BREATHING, + "Aquarium dry full-suit water breathing"); + checked++; + + require(!new ColdIronProperty().hasEffect( + new ItemStack(net.minecraft.init.Items.DIAMOND), coldIronFull), + "Cold-Iron property accepts an unrelated item"); + checked++; + + final EntityPlayer starSteelContract = armorTestPlayer(server, world, + "StarSteelContract"); + final ItemStack starSteelContractTrigger = equipArmor( + starSteelContract, MaterialNames.STARSTEEL, 1); + require(new StarSteelProperty().hasEffect( + starSteelContractTrigger, starSteelContract), + "Star-Steel property rejected its own equipped armor"); + checked++; + + final EntityPlayer starSteelTickPlayer = armorTestPlayer(server, world, + "StarSteelArmorTick"); + final ItemStack starSteelTickTrigger = equipArmor( + starSteelTickPlayer, MaterialNames.STARSTEEL, 4); + if (world.getTotalWorldTime() == 0L) { + world.getWorldInfo().setWorldTotalTime(1L); + } + starSteelTickTrigger.getItem().onArmorTick( + world, starSteelTickPlayer, starSteelTickTrigger); + starSteelTickTrigger.getItem().onArmorTick( + world, starSteelTickPlayer, starSteelTickTrigger); + requireEffect(starSteelTickPlayer, MobEffects.JUMP_BOOST, 3, + "Star-Steel armor-tick jump boost"); + requireEffect(starSteelTickPlayer, MobEffects.SPEED, 2, + "Star-Steel armor-tick speed boost"); + checked += 2; + + final BlockPos tickWaterFeet = new BlockPos(28, 80, 28); + final BlockPos tickWaterHead = tickWaterFeet.up(); + final net.minecraft.block.state.IBlockState originalTickFeet = + world.getBlockState(tickWaterFeet); + final net.minecraft.block.state.IBlockState originalTickHead = + world.getBlockState(tickWaterHead); + try { + world.setBlockState(tickWaterFeet, Blocks.WATER.getDefaultState(), 2); + world.setBlockState(tickWaterHead, Blocks.WATER.getDefaultState(), 2); + final EntityPlayer aquariumTickPlayer = armorTestPlayer(server, world, + "AquariumArmorTick"); + aquariumTickPlayer.setPosition(28.5D, 80.0D, 28.5D); + aquariumTickPlayer.handleWaterMovement(); + final ItemStack aquariumTickTrigger = equipArmor( + aquariumTickPlayer, MaterialNames.AQUARIUM, 4); + aquariumTickTrigger.getItem().onArmorTick( + world, aquariumTickPlayer, aquariumTickTrigger); + aquariumTickTrigger.getItem().onArmorTick( + world, aquariumTickPlayer, aquariumTickTrigger); + requireEffect(aquariumTickPlayer, MobEffects.WATER_BREATHING, 0, + "Aquarium armor-tick water breathing"); + requireEffect(aquariumTickPlayer, MobEffects.RESISTANCE, 0, + "Aquarium armor-tick resistance"); + checked += 2; + } finally { + world.setBlockState(tickWaterFeet, originalTickFeet, 2); + world.setBlockState(tickWaterHead, originalTickHead, 2); + } + + return checked; + } + + private static EntityPlayer armorTestPlayer( + final MinecraftServer server, + final WorldServer world, + final String name) { + return new ProbePlayer(world, + new GameProfile(UUID.nameUUIDFromBytes(name.getBytes()), name)); + } + + private static ItemStack equipArmor( + final EntityPlayer player, + final String materialName, + final int pieces) { + final MMDMaterial material = Materials.getMaterialByName(materialName); + final EntityEquipmentSlot[] slots = { + EntityEquipmentSlot.FEET, + EntityEquipmentSlot.LEGS, + EntityEquipmentSlot.CHEST, + EntityEquipmentSlot.HEAD + }; + final Names[] forms = { + Names.BOOTS, + Names.LEGGINGS, + Names.CHESTPLATE, + Names.HELMET + }; + ItemStack trigger = ItemStack.EMPTY; + for (int i = 0; i < pieces; i++) { + final ItemStack armor = new ItemStack(material.getItem(forms[i])); + player.setItemStackToSlot(slots[i], armor); + if (trigger.isEmpty()) { + trigger = armor; + } + } + return trigger; + } + + private static void requireEffect( + final EntityPlayer player, + final net.minecraft.potion.Potion potion, + final int amplifier, + final String description) { + final PotionEffect effect = player.getActivePotionEffect(potion); + require(effect != null, description + " was not applied"); + require(effect.getAmplifier() == amplifier, + description + " has amplifier " + effect.getAmplifier() + + ", expected " + amplifier); + } + + private static void requireNoEffect( + final EntityPlayer player, + final net.minecraft.potion.Potion potion, + final String description) { + require(player.getActivePotionEffect(potion) == null, + description + " was unexpectedly applied"); + } + + private static final class ProbePlayer extends EntityPlayer { + private ProbePlayer(final World world, final GameProfile profile) { + super(world, profile); + } + + @Override + public boolean isSpectator() { + return false; + } + + @Override + public boolean isCreative() { + return false; + } + } + + private static void verifyRailRecipe( + final World world, + final String recipePath, + final Item expectedItem, + final int expectedCount, + final Item... grid) { + require(grid.length == 9, "Rail recipe test grid must contain nine slots"); + final InventoryCrafting crafting = new InventoryCrafting(new Container() { + @Override + public boolean canInteractWith(final EntityPlayer playerIn) { + return false; + } + }, 3, 3); + for (int slot = 0; slot < grid.length; slot++) { + if (grid[slot] != null) { + crafting.setInventorySlotContents(slot, new ItemStack(grid[slot])); + } + } + + final ResourceLocation expectedRecipe = new ResourceLocation("basemetals", recipePath); + final IRecipe registeredRecipe = CraftingManager.REGISTRY.getObject(expectedRecipe); + require(registeredRecipe != null, "Crafting recipe was not registered: " + expectedRecipe); + require(registeredRecipe.matches(crafting, world), + "Registered crafting recipe did not match its canonical input: " + expectedRecipe); + final IRecipe recipe = CraftingManager.findMatchingRecipe(crafting, world); + require(recipe != null, "No crafting recipe matched " + expectedRecipe); + require(expectedRecipe.equals(recipe.getRegistryName()), + "Crafting input for " + expectedRecipe + " matched " + recipe.getRegistryName()); + + final ItemStack result = recipe.getCraftingResult(crafting); + require(!result.isEmpty(), "Crafting recipe " + expectedRecipe + " returned an empty result"); + require(result.getItem() == expectedItem, + "Crafting recipe " + expectedRecipe + " returned " + result.getItem().getRegistryName() + + ", expected " + expectedItem.getRegistryName()); + require(result.getCount() == expectedCount, + "Crafting recipe " + expectedRecipe + " returned " + result.getCount() + + " items, expected " + expectedCount); + } + + private static int verifyDoorAndTrapdoorRecipe( + final World world, + final Item ingredient, + final String material) { + requireCreativeRegistryEntry(material + "_door"); + requireCreativeRegistryEntry(material + "_trapdoor"); + verifyCraftingResult(world, ingredient, material + "_door", 3, 2, 3); + if ("quartz".equals(material)) { + verifyCraftingResult(world, Item.getItemFromBlock(Blocks.QUARTZ_BLOCK), + material + "_trapdoor", 1, 1, 1); + } else { + verifyCraftingResult(world, ingredient, material + "_trapdoor", 1, 2, 2); + } + return 2; + } + + private static void requireCreativeRegistryEntry(final String path) { + final ResourceLocation registryName = new ResourceLocation("basemetals", path); + final Block block = Block.REGISTRY.getObject(registryName); + require(block != null && registryName.equals(block.getRegistryName()), + "Missing registered block " + registryName); + final Item item = Item.REGISTRY.getObject(registryName); + require(item != null && registryName.equals(item.getRegistryName()), + "Missing registered item " + registryName); + require(item.getCreativeTab() != null, + "Registered item is absent from creative tabs: " + registryName); + } + + private static void verifyCraftingResult( + final World world, + final Item ingredient, + final String expectedPath, + final int expectedCount, + final int width, + final int height) { + final InventoryCrafting crafting = new InventoryCrafting(new Container() { + @Override + public boolean canInteractWith(final EntityPlayer playerIn) { + return false; + } + }, 3, 3); + for (int row = 0; row < height; row++) { + for (int column = 0; column < width; column++) { + crafting.setInventorySlotContents(column + row * 3, new ItemStack(ingredient)); + } + } + + final ResourceLocation expectedRecipe = new ResourceLocation("basemetals", expectedPath); + final IRecipe registeredRecipe = CraftingManager.REGISTRY.getObject(expectedRecipe); + require(registeredRecipe != null, "Crafting recipe was not registered: " + expectedRecipe); + require(registeredRecipe.matches(crafting, world), + "Registered crafting recipe did not match its canonical input: " + expectedRecipe); + final IRecipe recipe = CraftingManager.findMatchingRecipe(crafting, world); + require(recipe != null, "No crafting recipe matched " + expectedRecipe); + require(expectedRecipe.equals(recipe.getRegistryName()), + "Crafting input for " + expectedRecipe + " matched " + recipe.getRegistryName()); + + final ItemStack result = recipe.getCraftingResult(crafting); + require(!result.isEmpty(), "Crafting recipe " + expectedRecipe + " returned an empty result"); + require(expectedRecipe.equals(result.getItem().getRegistryName()), + "Crafting recipe " + expectedRecipe + " returned " + result.getItem().getRegistryName()); + require(result.getCount() == expectedCount, + "Crafting recipe " + expectedRecipe + " returned " + result.getCount() + + " items, expected " + expectedCount); + } + private static String requiredProperty(final String name) { final String value = System.getProperty(name); if (value == null || value.trim().isEmpty()) { @@ -81,6 +1320,14 @@ private static String version(final String modid) { throw new IllegalStateException("Missing loaded mod " + modid); } + private static Item requireItem(final String namespace, final String path) { + final ResourceLocation registryName = new ResourceLocation(namespace, path); + final Item item = Item.REGISTRY.getObject(registryName); + require(item != null && registryName.equals(item.getRegistryName()), + "Missing registered item " + registryName); + return item; + } + private static void requireRegistered(final Object value, final String registryName) { require(value != null, "Missing registry object " + registryName); } diff --git a/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsTinkersRuntimeProbe.java b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsTinkersRuntimeProbe.java new file mode 100644 index 00000000..5cfdca33 --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsTinkersRuntimeProbe.java @@ -0,0 +1,346 @@ +package com.mcmoddev.basemetals.test; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; + +import com.mcmoddev.basemetals.content.ContentMode; +import com.mcmoddev.basemetals.util.BMeConfig; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.FurnaceRecipes; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventHandler; +import net.minecraftforge.fml.common.event.FMLServerStartedEvent; +import net.minecraftforge.oredict.OreDictionary; +import com.mcmoddev.lib.registry.CrusherRecipeRegistry; +import slimeknights.tconstruct.library.TinkerRegistry; +import slimeknights.tconstruct.library.materials.Material; +import slimeknights.tconstruct.library.smeltery.AlloyRecipe; +import slimeknights.tconstruct.library.smeltery.MeltingRecipe; + +/** Test-only Tinkers/TAIGA compatibility probe. This class never enters the public jar. */ +@Mod( + modid = BaseMetalsTinkersRuntimeProbe.MODID, + name = "Base Metals Tinkers Runtime Probe", + version = "1", + dependencies = "required-after:basemetals;required-after:mmdlib;required-after:orespawn;" + + "required-after:mantle;required-after:tconstruct", + acceptedMinecraftVersions = "[1.12.2]") +public final class BaseMetalsTinkersRuntimeProbe { + public static final String MODID = "basemetals_tinkers_runtime_probe"; + + // The published TAIGA 1.3.4 jar retains 1.3.3 in its embedded mod metadata. + private static final String TAIGA_EMBEDDED_VERSION = "1.12.2-1.3.3"; + + private static final List ADAMANT_FORMS = Arrays.asList( + "oreAdamant", "blockAdamant", "plateAdamant", "doorAdamant", + "nuggetAdamant", "trapdoorAdamant", "dustAdamant", "gearAdamant", + "rodAdamant", "barsAdamant", "ingotAdamant", "dustTinyAdamant", + "dustSmallAdamant"); + + @EventHandler + public void serverStarted(final FMLServerStartedEvent event) throws IOException { + final boolean expectedTaiga = Boolean.parseBoolean( + requiredProperty("basemetals.probe.expectedTaiga")); + final boolean expectedPrismarine = Boolean.parseBoolean( + requiredProperty("basemetals.probe.expectedPrismarine")); + final boolean expectedConArm = Boolean.parseBoolean( + requiredProperty("basemetals.probe.expectedConArm")); + final ContentMode expectedContentMode = ContentMode.fromSerializedName( + requiredProperty("basemetals.probe.expectedContentMode")); + final File marker = new File(requiredProperty("basemetals.probe.marker")); + final Properties result = new Properties(); + + require(Loader.isModLoaded("basemetals"), "Base Metals did not load"); + require(Loader.isModLoaded("mmdlib"), "MMDLib did not load"); + require(Loader.isModLoaded("orespawn"), "OreSpawn did not load"); + require(Loader.isModLoaded("mantle"), "Mantle did not load"); + require(Loader.isModLoaded("tconstruct"), "Tinkers Construct did not load"); + require(BMeConfig.getActiveContentMode() == expectedContentMode, + "Content mode did not match expected mode " + expectedContentMode + + "; actual=" + BMeConfig.getActiveContentMode()); + require(Loader.isModLoaded("taiga") == expectedTaiga, + "TAIGA loaded state did not match expected state " + expectedTaiga); + require(Loader.isModLoaded("conarm") == expectedConArm, + "Construct's Armory loaded state did not match expected state " + expectedConArm); + verifyPrismarineConfiguration(expectedPrismarine); + verifyCoreContentPolicy(expectedContentMode); + + final Item adamantineIngot = requireItem("basemetals", "adamantine_ingot"); + verifyBaseAliases("Adamantine"); + verifyBaseAliases("Adamantite"); + verifyBaseAliases("Adamantium"); + + final Fluid adamantineFluid = requireFluid("adamantine"); + if (expectedContentMode == ContentMode.REALISM) { + require(meltingFluids(adamantineIngot).isEmpty(), + "Realism exposes Adamantine Tinkers melting outputs: " + + meltingFluids(adamantineIngot)); + } else { + require(meltingFluids(adamantineIngot).equals(singleton(adamantineFluid.getName())), + "Base Metals Adamantine ingot has ambiguous Tinkers melting outputs: " + + meltingFluids(adamantineIngot)); + } + verifyMaterialStats(expectedContentMode); + verifyArmorMaterialStats(expectedContentMode, expectedConArm); + + if (expectedTaiga) { + require(TAIGA_EMBEDDED_VERSION.equals(version("taiga")), + "Unexpected TAIGA version " + version("taiga")); + verifyNoBaseMetalsAdamantAliases(); + verifyTaigaAliases(); + + final Item taigaAdamantIngot = requireItem("taiga", "adamant_ingot"); + final Fluid taigaAdamantFluid = requireFluid("adamant_fluid"); + require(adamantineFluid != taigaAdamantFluid, + "Base Metals Adamantine and TAIGA Adamant share one fluid instance"); + require(meltingFluids(taigaAdamantIngot).equals(singleton(taigaAdamantFluid.getName())), + "TAIGA Adamant ingot has ambiguous Tinkers melting outputs: " + + meltingFluids(taigaAdamantIngot)); + } else { + verifyBaseAliases("Adamant"); + require(FluidRegistry.getFluid("adamant_fluid") == null, + "TAIGA Adamant fluid exists when TAIGA is absent"); + } + + result.setProperty("phase", System.getProperty("basemetals.probe.phase", "unknown")); + result.setProperty("taiga", Boolean.toString(expectedTaiga)); + result.setProperty("conarm", Boolean.toString(expectedConArm)); + result.setProperty("prismarine", Boolean.toString(expectedPrismarine)); + result.setProperty("contentMode", expectedContentMode.serializedName()); + if (expectedTaiga) { + result.setProperty("taigaEmbeddedVersion", version("taiga")); + } + result.setProperty("adamantineMeltingOutputs", + meltingFluids(adamantineIngot).toString()); + result.setProperty("registered", "true"); + marker.getParentFile().mkdirs(); + try (FileOutputStream output = new FileOutputStream(marker)) { + result.store(output, "Base Metals Tinkers/TAIGA qualification"); + } + FMLCommonHandler.instance().getMinecraftServerInstance().initiateShutdown(); + } + + private static void verifyArmorMaterialStats(final ContentMode mode, + final boolean expectedConArm) { + if (!expectedConArm) { + return; + } + final String allowed = mode == ContentMode.REALISM ? "nickel" : "adamantine"; + requireStats(allowed, allowed, "core", "plates", "trim"); + if (mode != ContentMode.HIGH_FANTASY) { + // Use a Base Metals-specific material here. Tinkers itself owns a + // pre-existing Lead material and its third-party stats remain + // authoritative even when Base Metals recipes are restricted. + final Material bismuth = TinkerRegistry.getMaterial("bismuth"); + require(bismuth != Material.UNKNOWN, + "Missing restricted-mode Tinkers material Bismuth"); + require(!bismuth.hasStats("core") && !bismuth.hasStats("plates") + && !bismuth.hasStats("trim"), + "Restricted mode exposed Bismuth Construct's Armory stats"); + } + } + + private static void verifyCoreContentPolicy(final ContentMode mode) { + // Registry identities and creative recovery remain stable in every mode. + for (final String path : Arrays.asList("adamantine_bow", "adamantine_pickaxe", + "pewter_chestplate", "bronze_pickaxe", "mercury_ingot")) { + final Item item = requireItem("basemetals", path); + require(item.getCreativeTab() != null, + "Restricted item is unavailable for creative recovery: " + path); + } + + final boolean high = mode == ContentMode.HIGH_FANTASY; + final boolean realism = mode == ContentMode.REALISM; + verifyRecipeOutput("adamantine_bow", high); + verifyRecipeOutput("adamantine_pickaxe", !realism); + verifyRecipeOutput("pewter_chestplate", high); + verifyRecipeOutput("bronze_pickaxe", true); + + final ItemStack adamantinePowder = new ItemStack( + requireItem("basemetals", "adamantine_powder")); + final ItemStack adamantineIngot = new ItemStack( + requireItem("basemetals", "adamantine_ingot")); + final ItemStack smelted = FurnaceRecipes.instance().getSmeltingResult(adamantinePowder); + require(smelted.isEmpty() == realism, + "Adamantine furnace acquisition does not match " + mode + ": " + smelted); + require((CrusherRecipeRegistry.getRecipeForInputItem(adamantineIngot) == null) == realism, + "Adamantine crusher acquisition does not match " + mode); + + final ItemStack mercuryPowder = new ItemStack( + requireItem("basemetals", "mercury_powder")); + final ItemStack mercurySmelted = FurnaceRecipes.instance().getSmeltingResult(mercuryPowder); + require(mercurySmelted.isEmpty() == realism, + "Mercury reagent ingot acquisition does not match " + mode + ": " + + mercurySmelted); + } + + private static void verifyRecipeOutput(final String path, final boolean expectedAllowed) { + final ResourceLocation id = new ResourceLocation("basemetals", path); + final IRecipe recipe = CraftingManager.REGISTRY.getObject(id); + require(recipe != null, "Missing stable recipe identity " + id); + require(!recipe.getRecipeOutput().isEmpty() == expectedAllowed, + "Recipe policy for " + id + " does not match expected allowed=" + + expectedAllowed + "; output=" + recipe.getRecipeOutput()); + require(recipe.isDynamic() != expectedAllowed, + "Recipe-book visibility for " + id + " does not match expected allowed=" + + expectedAllowed); + } + + private static void verifyMaterialStats(final ContentMode mode) { + if (mode == ContentMode.REALISM) { + require(TinkerRegistry.getMaterial("adamantine") == Material.UNKNOWN, + "Realism exposed mythical Adamantine as a Tinkers material"); + verifyRestrictedStats("nickel", "Nickel"); + return; + } + + if (mode == ContentMode.HIGH_FANTASY) { + requireStats("adamantine", "Adamantine", "head", "handle", "extra", "bow", + "bowstring", "shaft", "fletching"); + } else { + verifyRestrictedStats("adamantine", "Adamantine"); + } + } + + private static void verifyRestrictedStats(final String identifier, final String displayName) { + final Material material = TinkerRegistry.getMaterial(identifier); + require(material != Material.UNKNOWN, "Missing Tinkers material " + identifier); + requireStats(identifier, displayName, "head", "handle", "extra", "shaft", "fletching"); + require(!material.hasStats("bow"), displayName + " exposes restricted bow stats"); + require(!material.hasStats("bowstring"), + displayName + " exposes restricted bowstring stats"); + } + + private static void requireStats(final String materialIdentifier, final String displayName, + final String... identifiers) { + final Material material = TinkerRegistry.getMaterial(materialIdentifier); + require(material != Material.UNKNOWN, "Missing Tinkers material " + materialIdentifier); + for (final String identifier : identifiers) { + require(material.hasStats(identifier), + displayName + " is missing Tinkers stats " + identifier); + } + } + + private static void verifyPrismarineConfiguration(final boolean expectedPrismarine) { + final Fluid prismarine = FluidRegistry.getFluid("prismarine"); + if (expectedPrismarine) { + require(prismarine != null, "Prismarine fluid is missing when enabled"); + return; + } + + require(prismarine == null, "Prismarine fluid exists when Prismarine additions are disabled"); + for (final AlloyRecipe recipe : TinkerRegistry.getAlloys()) { + if (recipe.getResult() != null && recipe.getResult().getFluid() != null) { + require(!"aquarium".equals(recipe.getResult().getFluid().getName()), + "Aquarium alloy was registered without molten Prismarine"); + } + } + } + + private static void verifyBaseAliases(final String suffix) { + requireOreEntry("ingot" + suffix, "basemetals", "adamantine_ingot"); + requireOreEntry("dust" + suffix, "basemetals", "adamantine_powder"); + requireOreEntry("nugget" + suffix, "basemetals", "adamantine_nugget"); + requireOreEntry("block" + suffix, "basemetals", "adamantine_block"); + } + + private static void verifyNoBaseMetalsAdamantAliases() { + for (final String oreName : ADAMANT_FORMS) { + for (final ItemStack stack : OreDictionary.getOres(oreName, false)) { + final ResourceLocation registryName = stack.getItem().getRegistryName(); + require(registryName == null || !"basemetals".equals(registryName.getNamespace()), + "TAIGA-owned Ore Dictionary name " + oreName + + " contains Base Metals item " + registryName); + } + } + } + + private static void verifyTaigaAliases() { + requireOreEntry("ingotAdamant", "taiga", "adamant_ingot"); + requireOreEntry("dustAdamant", "taiga", "adamant_dust"); + requireOreEntry("nuggetAdamant", "taiga", "adamant_nugget"); + requireOreEntry("blockAdamant", "taiga", "adamant_block"); + } + + private static void requireOreEntry( + final String oreName, + final String namespace, + final String path) { + final ResourceLocation expected = new ResourceLocation(namespace, path); + final List actual = new ArrayList<>(); + boolean found = false; + for (final ItemStack stack : OreDictionary.getOres(oreName, false)) { + final ResourceLocation registryName = stack.getItem().getRegistryName(); + actual.add(registryName); + if (expected.equals(registryName)) { + found = true; + } + } + require(found, "Ore Dictionary name " + oreName + " is missing " + expected + + "; entries=" + actual); + } + + private static Set meltingFluids(final Item item) { + final ItemStack stack = new ItemStack(item); + final Set fluids = new LinkedHashSet<>(); + for (final MeltingRecipe recipe : TinkerRegistry.getAllMeltingRecipies()) { + if (recipe.matches(stack)) { + fluids.add(recipe.getResult().getFluid().getName()); + } + } + return fluids; + } + + private static Set singleton(final String value) { + final Set values = new LinkedHashSet<>(); + values.add(value); + return values; + } + + private static Item requireItem(final String namespace, final String path) { + final ResourceLocation registryName = new ResourceLocation(namespace, path); + final Item item = Item.REGISTRY.getObject(registryName); + require(item != null && registryName.equals(item.getRegistryName()), + "Missing item " + registryName); + return item; + } + + private static Fluid requireFluid(final String name) { + final Fluid fluid = FluidRegistry.getFluid(name); + require(fluid != null, "Missing fluid " + name); + return fluid; + } + + private static String version(final String modid) { + return Loader.instance().getIndexedModList().get(modid).getVersion(); + } + + private static String requiredProperty(final String name) { + final String value = System.getProperty(name); + if (value == null || value.trim().isEmpty()) { + throw new IllegalStateException("Missing system property " + name); + } + return value; + } + + private static void require(final boolean condition, final String message) { + if (!condition) { + throw new IllegalStateException(message); + } + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/util/BaseMetalsConfigContractTest.java b/src/test/java/com/mcmoddev/basemetals/util/BaseMetalsConfigContractTest.java new file mode 100644 index 00000000..a43c1fb3 --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/util/BaseMetalsConfigContractTest.java @@ -0,0 +1,196 @@ +package com.mcmoddev.basemetals.util; + +import com.mcmoddev.basemetals.content.ContentMode; +import net.minecraftforge.common.config.ConfigCategory; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.common.config.Property; +import org.apache.commons.lang3.text.WordUtils; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.nio.file.Path; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class BaseMetalsConfigContractTest { + private static final String[] METALS = { + "adamantine", "antimony", "aquarium", "bismuth", "brass", "bronze", + "coldiron", "copper", "cupronickel", "electrum", "invar", "lead", + "mercury", "mithril", "nickel", "pewter", "platinum", "silver", + "starsteel", "steel", "tin", "zinc" + }; + private static final String[] VANILLA = { + "charcoal", "coal", "diamond", "emerald", "gold", "iron", "stone", + "wood", "ender", "quartz", "obsidian", "lapis", "prismarine", "redstone" + }; + private static final Set VANILLA_FLUIDS = new LinkedHashSet<>(Arrays.asList( + "charcoal", "coal", "diamond", "emerald", "gold", "iron", "ender", + "quartz", "obsidian", "prismarine", "redstone")); + + @TempDir + Path tempDirectory; + + @Test + void exposesTheFiveHistoricalCategoriesAndNinetyThreeSettings() { + final Configuration configuration = create(); + final Set expectedCategories = BMeConfig.GUI_CATEGORIES.stream() + .map(name -> name.toLowerCase(java.util.Locale.ROOT)) + .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); + assertEquals(expectedCategories, new LinkedHashSet<>(configuration.getCategoryNames())); + assertEquals(2, configuration.getCategory(BMeConfig.GENERAL_CAT).size()); + assertEquals(22, configuration.getCategory(BMeConfig.MATERIALS_CAT).size()); + assertEquals(14, configuration.getCategory(BMeConfig.VANILLA_CAT).size()); + assertEquals(33, configuration.getCategory(BMeConfig.FLUIDS_CAT).size()); + assertEquals(22, configuration.getCategory(BMeConfig.FORCED_TRAITS_CAT).size()); + assertEquals(93, configuration.getCategoryNames().stream() + .mapToInt(name -> configuration.getCategory(name).size()).sum()); + } + + @Test + void preservesEveryKeyDefaultCommentAndMarksEveryOptionForRestart() { + final Configuration configuration = create(); + assertProperty(configuration, BMeConfig.GENERAL_CAT, "achievements", true, + "If false, then Base Metals Achievements will be disabled (This is currently required if you disable any metals", + "config.basemetals.option.achievements"); + final Property contentMode = configuration.getCategory(BMeConfig.GENERAL_CAT) + .get(BMeConfig.CONTENT_MODE_PROPERTY); + assertEquals(Property.Type.STRING, contentMode.getType()); + assertEquals(ContentMode.HIGH_FANTASY.serializedName(), contentMode.getString()); + assertEquals(Arrays.asList(ContentMode.serializedNames()), + Arrays.asList(contentMode.getValidValues())); + assertEquals(Arrays.asList(ContentMode.translationKeys()), + Arrays.asList(contentMode.getValidValuesDisplay())); + assertTrue(contentMode.requiresMcRestart()); + + for (final String material : METALS) { + final String display = WordUtils.capitalizeFully(material); + assertProperty(configuration, BMeConfig.MATERIALS_CAT, "Enable" + display, true, + "Enable " + display + " Items and Materials", materialKey(material)); + assertProperty(configuration, BMeConfig.FLUIDS_CAT, "Enabled " + display, true, + "Enable the molten fluid of " + material, materialKey(material)); + assertProperty(configuration, BMeConfig.FORCED_TRAITS_CAT, + "Force" + display + "TraitRegistration", false, + "Enable the forced registration of traits for " + material, + materialKey(material)); + } + + for (final String material : VANILLA) { + final String display = WordUtils.capitalizeFully(material); + assertProperty(configuration, BMeConfig.VANILLA_CAT, "Enable" + display, true, + "Enable " + display + " Additions like Walls, Slabs and Pressure-plates", + materialKey(material)); + if (VANILLA_FLUIDS.contains(material)) { + assertProperty(configuration, BMeConfig.FLUIDS_CAT, "Enabled " + display, true, + "Enable the molten fluid of " + material, materialKey(material)); + } + } + + for (final String categoryName : BMeConfig.GUI_CATEGORIES) { + final ConfigCategory category = configuration.getCategory(categoryName); + assertTrue(category.requiresMcRestart(), categoryName); + assertTrue(category.requiresWorldRestart(), categoryName); + assertNotNull(category.getLanguagekey(), categoryName); + for (final Property property : category.getValues().values()) { + if (!BMeConfig.CONTENT_MODE_PROPERTY.equals(property.getName())) { + assertEquals(Property.Type.BOOLEAN, property.getType(), property.getName()); + } + } + } + } + + @Test + void missingLegacyModeAndExplicitHighFantasyHaveTheSameEffectiveValue() { + final Configuration legacy = new Configuration( + tempDirectory.resolve("LegacyBaseMetals.cfg").toFile()); + legacy.get(BMeConfig.GENERAL_CAT, "achievements", false); + assertEquals(ContentMode.HIGH_FANTASY, BMeConfig.configuredContentMode(legacy)); + assertFalse(legacy.getCategory(BMeConfig.GENERAL_CAT).containsKey( + BMeConfig.CONTENT_MODE_PROPERTY)); + + BMeConfig.populateConfiguration(legacy); + assertEquals(ContentMode.HIGH_FANTASY, BMeConfig.configuredContentMode(legacy)); + assertFalse(legacy.getCategory(BMeConfig.GENERAL_CAT).get("achievements").getBoolean()); + } + + @Test + void missingPropertyDefaultsToHighFantasyAndInvalidValuesAreCorrectedOnPopulate() { + final Configuration absent = create(); + absent.getCategory(BMeConfig.GENERAL_CAT).remove(BMeConfig.CONTENT_MODE_PROPERTY); + assertEquals(ContentMode.HIGH_FANTASY, BMeConfig.configuredContentMode(absent)); + + final Configuration invalid = create(); + invalid.getCategory(BMeConfig.GENERAL_CAT).get(BMeConfig.CONTENT_MODE_PROPERTY) + .set("not_a_mode"); + BMeConfig.populateConfiguration(invalid); + assertEquals(ContentMode.HIGH_FANTASY, BMeConfig.configuredContentMode(invalid)); + assertEquals(ContentMode.HIGH_FANTASY.serializedName(), + invalid.getCategory(BMeConfig.GENERAL_CAT) + .get(BMeConfig.CONTENT_MODE_PROPERTY).getString()); + } + + @Test + void legacyUpgradePreservesEveryExistingBooleanValue() { + final Configuration legacy = create(); + final Map expected = new LinkedHashMap<>(); + int index = 0; + for (final String categoryName : BMeConfig.GUI_CATEGORIES) { + for (final Property property : legacy.getCategory(categoryName).getValues().values()) { + if (property.getType() == Property.Type.BOOLEAN) { + final boolean value = (index++ & 1) == 0; + property.set(value); + expected.put(categoryName + "\u0000" + property.getName(), value); + } + } + } + legacy.getCategory(BMeConfig.GENERAL_CAT).remove(BMeConfig.CONTENT_MODE_PROPERTY); + legacy.save(); + + final Configuration upgraded = create(); + assertEquals(ContentMode.HIGH_FANTASY, BMeConfig.configuredContentMode(upgraded)); + for (final Map.Entry entry : expected.entrySet()) { + final String[] key = entry.getKey().split("\u0000", 2); + assertEquals(entry.getValue().booleanValue(), + upgraded.getCategory(key[0]).get(key[1]).getBoolean(), entry.getKey()); + } + } + + @Test + void generatedMaterialMapMatchesTheElevenStableProviderRules() { + assertEquals(11, BMeConfig.getGeneratedOreRules().size()); + assertEquals("basemetals:legacy/coldiron_ore", + BMeConfig.getGeneratedOreRules().get("coldiron")); + assertEquals("basemetals:legacy/platinum_ore", + BMeConfig.getGeneratedOreRules().get("platinum")); + assertFalse(BMeConfig.getGeneratedOreRules().containsKey("antimony")); + assertFalse(BMeConfig.getGeneratedOreRules().containsKey("bismuth")); + } + + private Configuration create() { + return TestConfigFactory.create(tempDirectory.resolve("BaseMetals.cfg").toFile()); + } + + private static void assertProperty(final Configuration configuration, final String category, + final String name, final boolean expectedDefault, final String expectedComment, + final String expectedLanguageKey) { + final Property property = configuration.getCategory(category).get(name); + assertNotNull(property, category + "/" + name); + assertEquals(expectedDefault, Boolean.parseBoolean(property.getDefault()), name); + assertEquals(expectedComment + " [default: " + expectedDefault + "]", + property.getComment(), name); + assertEquals(expectedLanguageKey, property.getLanguageKey(), name); + assertTrue(property.requiresMcRestart(), name); + assertTrue(property.requiresWorldRestart(), name); + } + + private static String materialKey(final String material) { + return "config.basemetals.material." + material; + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/util/TestConfigFactory.java b/src/test/java/com/mcmoddev/basemetals/util/TestConfigFactory.java new file mode 100644 index 00000000..71d6d8dd --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/util/TestConfigFactory.java @@ -0,0 +1,30 @@ +package com.mcmoddev.basemetals.util; + +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.fml.relauncher.FMLInjectionData; + +import java.io.File; +import java.lang.reflect.Field; + +/** Test-only factory for a disposable Base Metals configuration. */ +public final class TestConfigFactory { + private TestConfigFactory() { + } + + public static Configuration create(final File file) { + prepareForgeConfigurationHome(file.getParentFile()); + final Configuration configuration = new Configuration(file); + BMeConfig.populateConfiguration(configuration); + return configuration; + } + + private static void prepareForgeConfigurationHome(final File home) { + try { + final Field minecraftHome = FMLInjectionData.class.getDeclaredField("minecraftHome"); + minecraftHome.setAccessible(true); + minecraftHome.set(null, home); + } catch (ReflectiveOperationException failure) { + throw new IllegalStateException("Could not initialize disposable Forge config home", failure); + } + } +} diff --git a/src/test/java/com/mcmoddev/lib/util/ConfigTests.java b/src/test/java/com/mcmoddev/lib/util/ConfigTests.java index bf4a6b59..6c4f5691 100644 --- a/src/test/java/com/mcmoddev/lib/util/ConfigTests.java +++ b/src/test/java/com/mcmoddev/lib/util/ConfigTests.java @@ -1,10 +1,7 @@ package com.mcmoddev.lib.util; -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import com.mcmoddev.lib.util.Config.Options; @@ -13,21 +10,8 @@ class ConfigTests { private static final String name = "TestMod"; - @BeforeAll - static void setUpBeforeClass() throws Exception { - // MODID = BaseMetals.MODID - } - - @AfterAll - static void tearDownAfterClass() throws Exception { - } - - @BeforeEach - void setUp() throws Exception { - } - @AfterEach - void tearDown() throws Exception { + void clearOptions() { Options.clearOptions(); } diff --git a/src/test/resources/orespawn3/basemetals-custom.json b/src/test/resources/orespawn3/basemetals-custom.json new file mode 100644 index 00000000..398b7cef --- /dev/null +++ b/src/test/resources/orespawn3/basemetals-custom.json @@ -0,0 +1,264 @@ +{ + "version": "2.0", + "spawns": { + "coldiron_ore": { + "retrogen": false, + "enabled": true, + "feature": "default", + "replaces": "default", + "dimensions": [ + -1 + ], + "biomes": { + "excludes": [] + }, + "parameters": { + "size": 8, + "variation": 4, + "frequency": 5, + "minHeight": 0, + "maxHeight": 128 + }, + "blocks": [ + { + "name": "basemetals:coldiron_ore", + "chance": 100 + } + ] + }, + "adamantine_ore": { + "retrogen": false, + "enabled": true, + "feature": "default", + "replaces": "default", + "dimensions": [ + -1 + ], + "biomes": { + "excludes": [] + }, + "parameters": { + "size": 8, + "variation": 4, + "frequency": 2, + "minHeight": 0, + "maxHeight": 128 + }, + "blocks": [ + { + "name": "basemetals:adamantine_ore", + "chance": 100 + } + ] + }, + "starsteel_ore": { + "retrogen": false, + "enabled": true, + "feature": "default", + "replaces": "default", + "dimensions": [ + 1 + ], + "biomes": { + "excludes": [] + }, + "parameters": { + "size": 8, + "variation": 4, + "frequency": 5, + "minHeight": 0, + "maxHeight": 255 + }, + "blocks": [ + { + "name": "basemetals:starsteel_ore", + "chance": 100 + } + ] + }, + "copper_ore": { + "retrogen": false, + "enabled": false, + "feature": "default", + "replaces": "default", + "dimensions": [], + "biomes": { + "excludes": [] + }, + "parameters": { + "size": 8, + "variation": 4, + "frequency": 10, + "minHeight": 0, + "maxHeight": 96 + }, + "blocks": [ + { + "name": "basemetals:copper_ore", + "chance": 100 + } + ] + }, + "silver_ore": { + "retrogen": false, + "enabled": true, + "feature": "default", + "replaces": "default", + "dimensions": [], + "biomes": { + "excludes": [] + }, + "parameters": { + "size": 8, + "variation": 4, + "frequency": 4, + "minHeight": 0, + "maxHeight": 32 + }, + "blocks": [ + { + "name": "basemetals:silver_ore", + "chance": 100 + } + ] + }, + "tin_ore": { + "retrogen": false, + "enabled": true, + "feature": "default", + "replaces": "default", + "dimensions": [], + "biomes": { + "excludes": [] + }, + "parameters": { + "size": 8, + "variation": 4, + "frequency": 10, + "minHeight": 0, + "maxHeight": 128 + }, + "blocks": [ + { + "name": "basemetals:tin_ore", + "chance": 100 + } + ] + }, + "lead_ore": { + "retrogen": false, + "enabled": true, + "feature": "default", + "replaces": "default", + "dimensions": [], + "biomes": { + "excludes": [] + }, + "parameters": { + "size": 8, + "variation": 4, + "frequency": 5, + "minHeight": 0, + "maxHeight": 64 + }, + "blocks": [ + { + "name": "basemetals:lead_ore", + "chance": 100 + } + ] + }, + "zinc_ore": { + "retrogen": false, + "enabled": true, + "feature": "default", + "replaces": "default", + "dimensions": [], + "biomes": { + "excludes": [] + }, + "parameters": { + "size": 8, + "variation": 4, + "frequency": 5, + "minHeight": 0, + "maxHeight": 96 + }, + "blocks": [ + { + "name": "basemetals:zinc_ore", + "chance": 100 + } + ] + }, + "mercury_ore": { + "retrogen": false, + "enabled": true, + "feature": "default", + "replaces": "default", + "dimensions": [], + "biomes": { + "excludes": [] + }, + "parameters": { + "size": 8, + "variation": 4, + "frequency": 3, + "minHeight": 0, + "maxHeight": 32 + }, + "blocks": [ + { + "name": "basemetals:mercury_ore", + "chance": 100 + } + ] + }, + "nickel_ore": { + "retrogen": false, + "enabled": true, + "feature": "default", + "replaces": "default", + "dimensions": [], + "biomes": { + "excludes": [] + }, + "parameters": { + "size": 8, + "variation": 4, + "frequency": 2.5, + "minHeight": 32, + "maxHeight": 96 + }, + "blocks": [ + { + "name": "basemetals:nickel_ore", + "chance": 100 + } + ] + }, + "platinum_ore": { + "retrogen": false, + "enabled": true, + "feature": "default", + "replaces": "default", + "dimensions": [], + "biomes": { + "excludes": [] + }, + "parameters": { + "size": 8, + "variation": 4, + "frequency": 0.125, + "minHeight": 1, + "maxHeight": 32 + }, + "blocks": [ + { + "name": "basemetals:platinum_ore", + "chance": 100 + } + ] + } + } +} diff --git a/src/main/resources/assets/basemetals/orespawn/basemetals.json b/src/test/resources/orespawn3/basemetals-stock.json similarity index 99% rename from src/main/resources/assets/basemetals/orespawn/basemetals.json rename to src/test/resources/orespawn3/basemetals-stock.json index 0899d53c..4b481884 100644 --- a/src/main/resources/assets/basemetals/orespawn/basemetals.json +++ b/src/test/resources/orespawn3/basemetals-stock.json @@ -261,4 +261,4 @@ ] } } -} \ No newline at end of file +} From 40cfc7fc369af769826725b9e0ef3396ffb48146 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Thu, 1 Oct 2026 11:11:24 +0100 Subject: [PATCH 5/6] Finish Base Metals 2.6.0 for Minecraft 1.12.2 Fix the accepted gameplay bugs, restore achievements and recipe-book unlocks, finish plate repairs, and add the optional Low Fantasy mode. Keep saved item and block IDs and the High Fantasy default. Update the player guides and release notes, and keep agent files and generated evidence out of Git. - #473: Remove metal fuel values while keeping coal and charcoal fuel. https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues/473 - #474: Separate door and trapdoor recipes and register Vanilla Bits forms. https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues/474 - #467: Separate TAIGA's Adamant alias, apply fishing-rod durability, produce 16 Steel rails, fire bolts on the server, use material-based shot damage, repair bolt rendering, and retain picked-up arrow identity. https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues/467 - #470 and #450: Count equipped armor by item identity, not stack damage, so Aquarium and Starsteel effects apply correctly. https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues/470 https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues/450 - #455: Skip Tinkers recipes when their materials or fluids are disabled. https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues/455 - #449: Return the tool-material enum name expected by Ancient Warfare 2. https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues/449 - #448 and #428: Use OreSpawn 4.1 as the sole ore generator, preserve migrated rule settings, and support disabled rules without fallback generation. https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues/448 https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues/428 - #468: Replace the retired build pipeline with ForgeGradle 7, pinned dependencies, runtime tests, reproducible jars, and guarded releases. https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues/468 --- .gitignore | 9 + CHANGELOG.txt | 66 +- README.md | 197 +- build.gradle | 10 +- docs/configuration.md | 34 +- docs/world-generation.md | 13 +- gradle/README.md | 10 +- gradle/data/gameplay-advancements.gradle | 73 + gradle/data/recipe-advancements.gradle | 160 + gradle/release/artifacts.gradle | 36 +- gradle/release/publishing.gradle | 2 +- .../verification/packaged-advancements.gradle | 104 + .../packaged-forge-dependencies.gradle | 2 +- .../packaged-forge-tinkers.gradle | 56 +- gradle/verification/packaged-forge.gradle | 17 + gradle/verification/support.gradle | 8 +- gradle/verification/workflows.gradle | 2 +- .../com/mcmoddev/basemetals/BaseMetals.java | 25 +- .../com/mcmoddev/basemetals/ModelDataFix.java | 109 +- .../advancement/AchievementCondition.java | 29 + .../advancement/GameplayAdvancements.java | 167 + .../client/config/BaseMetalsConfigScreen.java | 43 +- .../client/config/BaseMetalsGuiFactory.java | 32 + .../client/renderer/RenderBaseMetalsBolt.java | 17 +- .../basemetals/content/ContentMode.java | 13 +- .../basemetals/content/ContentPolicy.java | 60 +- .../basemetals/content/MaterialForm.java | 10 +- .../com/mcmoddev/basemetals/init/Blocks.java | 6 +- .../com/mcmoddev/basemetals/init/Fluids.java | 2 +- .../com/mcmoddev/basemetals/init/Items.java | 40 +- .../mcmoddev/basemetals/init/Materials.java | 216 +- .../com/mcmoddev/basemetals/init/Recipes.java | 6 +- .../basemetals/init/VillagerTrades.java | 12 + .../plugins/BMeConstructsArmory.java | 120 +- .../integration/plugins/BMeDenseOres.java | 10 +- .../integration/plugins/BMeEnderIO.java | 42 +- .../integration/plugins/BMeIC2.java | 8 +- .../integration/plugins/BMeMekanism.java | 6 +- .../integration/plugins/BMeThaumcraft.java | 115 +- .../plugins/BMeThermalExpansion.java | 31 +- .../plugins/BMeTinkersConstruct.java | 118 +- .../basemetals/items/ItemBaseMetalsArrow.java | 7 + .../basemetals/items/ItemBaseMetalsBolt.java | 2 + .../basemetals/items/ItemBaseMetalsBow.java | 22 +- .../items/ItemBaseMetalsCrossbow.java | 34 +- .../basemetals/items/ItemBaseMetalsHoe.java | 8 +- .../items/MaterialRangedDamage.java | 10 +- .../loot/ContentModeLootCondition.java | 2 +- .../network/ContentModeMessage.java | 2 +- .../network/ContentModeNetwork.java | 15 +- .../properties/AdamantineProperty.java | 19 +- .../properties/AdamantineToolProperty.java | 15 +- .../properties/AquariumProperty.java | 19 +- .../properties/AquariumToolProperty.java | 15 +- .../properties/BMEPropertiesHelper.java | 29 +- .../properties/BMEPropertyBase.java | 4 +- .../properties/ColdIronProperty.java | 17 +- .../properties/ColdIronToolProperty.java | 15 +- .../basemetals/properties/LeadProperty.java | 19 +- .../properties/MithrilProperty.java | 55 +- .../properties/MithrilToolProperty.java | 18 +- .../properties/StarSteelProperty.java | 21 +- .../basemetals/proxy/ClientProxy.java | 9 +- .../basemetals/proxy/CommonProxy.java | 5 +- .../recipe/ContentAcquisitionFilters.java | 13 +- .../basemetals/recipe/PlateRepairFactory.java | 63 + .../basemetals/recipe/PlateRepairRecipe.java | 100 + .../recipe/PolicyCrusherRecipe.java | 5 +- .../basemetals/recipe/PolicyRecipe.java | 7 +- .../mcmoddev/basemetals/util/BMeConfig.java | 110 +- .../basemetals/util/EventHandler.java | 26 +- .../basemetals/util/VillagerTradeHelper.java | 47 +- .../VanillaBitsRegistryEvents.java | 82 +- .../basemetals/vanillabits/VanillaBlocks.java | 29 +- .../basemetals/vanillabits/VanillaFluids.java | 18 +- .../basemetals/vanillabits/VanillaItems.java | 150 +- .../worldgen/BaseMetalsWorldgenProvider.java | 40 +- .../basemetals/advancements/_factories.json | 8 + .../assets/basemetals/lang/de_de.lang | 8 +- .../assets/basemetals/lang/en_au.lang | 9 +- .../assets/basemetals/lang/en_ca.lang | 9 +- .../assets/basemetals/lang/en_en.lang | 9 +- .../assets/basemetals/lang/en_gb.lang | 9 +- .../assets/basemetals/lang/en_pt.lang | 9 +- .../assets/basemetals/lang/en_us.lang | 7 +- .../assets/basemetals/lang/es_es.lang | 9 +- .../assets/basemetals/lang/es_mx.lang | 9 +- .../assets/basemetals/lang/fr_ca.lang | 9 +- .../assets/basemetals/lang/fr_fr.lang | 9 +- .../assets/basemetals/lang/it_it.lang | 9 +- .../assets/basemetals/lang/ja_jp.lang | 42 +- .../assets/basemetals/lang/nl_nl.lang | 9 +- .../assets/basemetals/lang/pt_br.lang | 9 +- .../assets/basemetals/lang/ru_ru.lang | 8 +- .../assets/basemetals/lang/zh_cn.lang | 7 +- .../assets/basemetals/lang/zh_tw.lang | 7 +- .../assets/basemetals/recipes/_factories.json | 2 +- .../basemetals/recipes/activator_rail.json | 2 +- .../basemetals/recipes/adamantine_anvil.json | 2 +- .../basemetals/recipes/adamantine_arrow.json | 4 +- .../basemetals/recipes/adamantine_axe.json | 4 +- .../basemetals/recipes/adamantine_bars_1.json | 4 +- .../basemetals/recipes/adamantine_bars_2.json | 4 +- .../basemetals/recipes/adamantine_block.json | 4 +- .../recipes/adamantine_block_ingot.json | 4 +- .../basemetals/recipes/adamantine_bolt.json | 4 +- .../basemetals/recipes/adamantine_boots.json | 4 +- .../adamantine_boots_plate_repair.json | 2 +- .../basemetals/recipes/adamantine_bow.json | 4 +- .../basemetals/recipes/adamantine_button.json | 4 +- .../recipes/adamantine_chestplate.json | 4 +- .../adamantine_chestplate_plate_repair.json | 2 +- .../recipes/adamantine_crackhammer.json | 4 +- .../recipes/adamantine_crossbow.json | 4 +- .../basemetals/recipes/adamantine_door.json | 4 +- .../recipes/adamantine_fishingrod.json | 4 +- .../basemetals/recipes/adamantine_gear.json | 4 +- .../basemetals/recipes/adamantine_helmet.json | 4 +- .../adamantine_helmet_plate_repair.json | 2 +- .../basemetals/recipes/adamantine_hoe.json | 4 +- .../recipes/adamantine_horsearmor.json | 4 +- .../basemetals/recipes/adamantine_ingot.json | 4 +- .../recipes/adamantine_leggings.json | 4 +- .../adamantine_leggings_plate_repair.json | 2 +- .../basemetals/recipes/adamantine_lever.json | 4 +- .../basemetals/recipes/adamantine_nugget.json | 4 +- .../recipes/adamantine_pickaxe.json | 4 +- .../basemetals/recipes/adamantine_plate.json | 4 +- .../basemetals/recipes/adamantine_powder.json | 4 +- .../recipes/adamantine_pressureplate.json | 4 +- .../basemetals/recipes/adamantine_rod.json | 3 +- .../basemetals/recipes/adamantine_scythe.json | 2 +- .../basemetals/recipes/adamantine_shears.json | 4 +- .../basemetals/recipes/adamantine_shield.json | 2 +- .../adamantine_shield_plate_repair.json | 2 +- .../basemetals/recipes/adamantine_shovel.json | 4 +- .../basemetals/recipes/adamantine_slab.json | 4 +- .../recipes/adamantine_smallpowder.json | 4 +- .../basemetals/recipes/adamantine_stairs.json | 4 +- .../basemetals/recipes/adamantine_sword.json | 4 +- .../recipes/adamantine_trapdoor.json | 4 +- .../basemetals/recipes/adamantine_wall.json | 4 +- .../basemetals/recipes/antimony_arrow.json | 4 +- .../basemetals/recipes/antimony_axe.json | 4 +- .../basemetals/recipes/antimony_bars_1.json | 4 +- .../basemetals/recipes/antimony_bars_2.json | 4 +- .../basemetals/recipes/antimony_block.json | 4 +- .../recipes/antimony_block_ingot.json | 4 +- .../basemetals/recipes/antimony_bolt.json | 4 +- .../basemetals/recipes/antimony_boots.json | 4 +- .../recipes/antimony_boots_plate_repair.json | 2 +- .../basemetals/recipes/antimony_bow.json | 4 +- .../basemetals/recipes/antimony_button.json | 4 +- .../recipes/antimony_chestplate.json | 4 +- .../antimony_chestplate_plate_repair.json | 2 +- .../recipes/antimony_crackhammer.json | 4 +- .../basemetals/recipes/antimony_crossbow.json | 4 +- .../basemetals/recipes/antimony_door.json | 4 +- .../recipes/antimony_fishingrod.json | 4 +- .../basemetals/recipes/antimony_gear.json | 4 +- .../basemetals/recipes/antimony_helmet.json | 4 +- .../recipes/antimony_helmet_plate_repair.json | 2 +- .../basemetals/recipes/antimony_hoe.json | 4 +- .../recipes/antimony_horsearmor.json | 4 +- .../basemetals/recipes/antimony_ingot.json | 4 +- .../basemetals/recipes/antimony_leggings.json | 4 +- .../antimony_leggings_plate_repair.json | 2 +- .../basemetals/recipes/antimony_lever.json | 4 +- .../basemetals/recipes/antimony_nugget.json | 4 +- .../basemetals/recipes/antimony_pickaxe.json | 4 +- .../basemetals/recipes/antimony_plate.json | 4 +- .../basemetals/recipes/antimony_powder.json | 4 +- .../recipes/antimony_pressureplate.json | 4 +- .../basemetals/recipes/antimony_rod.json | 3 +- .../basemetals/recipes/antimony_scythe.json | 2 +- .../basemetals/recipes/antimony_shears.json | 4 +- .../basemetals/recipes/antimony_shield.json | 2 +- .../recipes/antimony_shield_plate_repair.json | 2 +- .../basemetals/recipes/antimony_shovel.json | 4 +- .../basemetals/recipes/antimony_slab.json | 4 +- .../recipes/antimony_smallpowder.json | 4 +- .../basemetals/recipes/antimony_stairs.json | 4 +- .../basemetals/recipes/antimony_sword.json | 4 +- .../basemetals/recipes/antimony_trapdoor.json | 4 +- .../basemetals/recipes/antimony_wall.json | 4 +- .../basemetals/recipes/aquarium_arrow.json | 4 +- .../basemetals/recipes/aquarium_axe.json | 4 +- .../basemetals/recipes/aquarium_bars_1.json | 4 +- .../basemetals/recipes/aquarium_bars_2.json | 4 +- .../recipes/aquarium_blend_base.json | 4 +- .../recipes/aquarium_blend_smallblend.json | 4 +- .../basemetals/recipes/aquarium_block.json | 4 +- .../recipes/aquarium_block_ingot.json | 4 +- .../basemetals/recipes/aquarium_bolt.json | 4 +- .../basemetals/recipes/aquarium_boots.json | 4 +- .../basemetals/recipes/aquarium_bow.json | 4 +- .../basemetals/recipes/aquarium_button.json | 4 +- .../recipes/aquarium_chestplate.json | 4 +- .../recipes/aquarium_crackhammer.json | 4 +- .../basemetals/recipes/aquarium_crossbow.json | 4 +- .../basemetals/recipes/aquarium_door.json | 4 +- .../recipes/aquarium_fishingrod.json | 4 +- .../basemetals/recipes/aquarium_gear.json | 4 +- .../basemetals/recipes/aquarium_helmet.json | 4 +- .../basemetals/recipes/aquarium_hoe.json | 4 +- .../recipes/aquarium_horsearmor.json | 4 +- .../basemetals/recipes/aquarium_ingot.json | 4 +- .../basemetals/recipes/aquarium_leggings.json | 4 +- .../basemetals/recipes/aquarium_lever.json | 4 +- .../basemetals/recipes/aquarium_nugget.json | 4 +- .../basemetals/recipes/aquarium_pickaxe.json | 4 +- .../basemetals/recipes/aquarium_plate.json | 4 +- .../basemetals/recipes/aquarium_powder.json | 4 +- .../recipes/aquarium_pressureplate.json | 4 +- .../basemetals/recipes/aquarium_rod.json | 3 +- .../basemetals/recipes/aquarium_scythe.json | 2 +- .../basemetals/recipes/aquarium_shears.json | 4 +- .../basemetals/recipes/aquarium_shield.json | 2 +- .../basemetals/recipes/aquarium_shovel.json | 4 +- .../basemetals/recipes/aquarium_slab.json | 4 +- .../recipes/aquarium_smallblend_blend.json | 4 +- .../recipes/aquarium_smallpowder.json | 4 +- .../basemetals/recipes/aquarium_stairs.json | 4 +- .../basemetals/recipes/aquarium_sword.json | 4 +- .../basemetals/recipes/aquarium_trapdoor.json | 4 +- .../basemetals/recipes/aquarium_wall.json | 4 +- .../basemetals/recipes/bismuth_arrow.json | 4 +- .../basemetals/recipes/bismuth_axe.json | 4 +- .../basemetals/recipes/bismuth_bars_1.json | 4 +- .../basemetals/recipes/bismuth_bars_2.json | 4 +- .../basemetals/recipes/bismuth_block.json | 4 +- .../recipes/bismuth_block_ingot.json | 4 +- .../basemetals/recipes/bismuth_bolt.json | 4 +- .../basemetals/recipes/bismuth_boots.json | 4 +- .../recipes/bismuth_boots_plate_repair.json | 2 +- .../basemetals/recipes/bismuth_bow.json | 4 +- .../basemetals/recipes/bismuth_button.json | 4 +- .../recipes/bismuth_chestplate.json | 4 +- .../bismuth_chestplate_plate_repair.json | 2 +- .../recipes/bismuth_crackhammer.json | 4 +- .../basemetals/recipes/bismuth_crossbow.json | 4 +- .../basemetals/recipes/bismuth_door.json | 4 +- .../recipes/bismuth_fishingrod.json | 4 +- .../basemetals/recipes/bismuth_gear.json | 4 +- .../basemetals/recipes/bismuth_helmet.json | 4 +- .../recipes/bismuth_helmet_plate_repair.json | 2 +- .../basemetals/recipes/bismuth_hoe.json | 4 +- .../recipes/bismuth_horsearmor.json | 4 +- .../basemetals/recipes/bismuth_ingot.json | 4 +- .../basemetals/recipes/bismuth_leggings.json | 4 +- .../bismuth_leggings_plate_repair.json | 2 +- .../basemetals/recipes/bismuth_lever.json | 4 +- .../basemetals/recipes/bismuth_nugget.json | 4 +- .../basemetals/recipes/bismuth_pickaxe.json | 4 +- .../basemetals/recipes/bismuth_plate.json | 4 +- .../basemetals/recipes/bismuth_powder.json | 4 +- .../recipes/bismuth_pressureplate.json | 4 +- .../basemetals/recipes/bismuth_rod.json | 3 +- .../basemetals/recipes/bismuth_scythe.json | 2 +- .../basemetals/recipes/bismuth_shears.json | 4 +- .../basemetals/recipes/bismuth_shield.json | 2 +- .../recipes/bismuth_shield_plate_repair.json | 2 +- .../basemetals/recipes/bismuth_shovel.json | 4 +- .../basemetals/recipes/bismuth_slab.json | 4 +- .../recipes/bismuth_smallpowder.json | 4 +- .../basemetals/recipes/bismuth_stairs.json | 4 +- .../basemetals/recipes/bismuth_sword.json | 4 +- .../basemetals/recipes/bismuth_trapdoor.json | 4 +- .../basemetals/recipes/bismuth_wall.json | 4 +- .../basemetals/recipes/brass_arrow.json | 4 +- .../assets/basemetals/recipes/brass_axe.json | 4 +- .../basemetals/recipes/brass_bars_1.json | 4 +- .../basemetals/recipes/brass_bars_2.json | 4 +- .../basemetals/recipes/brass_blend_base.json | 4 +- .../recipes/brass_blend_smallblend.json | 4 +- .../basemetals/recipes/brass_block.json | 4 +- .../basemetals/recipes/brass_block_ingot.json | 4 +- .../assets/basemetals/recipes/brass_bolt.json | 4 +- .../basemetals/recipes/brass_boots.json | 4 +- .../recipes/brass_boots_plate_repair.json | 2 +- .../assets/basemetals/recipes/brass_bow.json | 4 +- .../basemetals/recipes/brass_button.json | 4 +- .../basemetals/recipes/brass_chestplate.json | 4 +- .../brass_chestplate_plate_repair.json | 2 +- .../basemetals/recipes/brass_crackhammer.json | 4 +- .../basemetals/recipes/brass_crossbow.json | 4 +- .../assets/basemetals/recipes/brass_door.json | 4 +- .../basemetals/recipes/brass_fishingrod.json | 4 +- .../assets/basemetals/recipes/brass_gear.json | 4 +- .../basemetals/recipes/brass_helmet.json | 4 +- .../recipes/brass_helmet_plate_repair.json | 2 +- .../assets/basemetals/recipes/brass_hoe.json | 4 +- .../basemetals/recipes/brass_horsearmor.json | 4 +- .../basemetals/recipes/brass_ingot.json | 4 +- .../basemetals/recipes/brass_leggings.json | 4 +- .../recipes/brass_leggings_plate_repair.json | 2 +- .../basemetals/recipes/brass_lever.json | 4 +- .../basemetals/recipes/brass_nugget.json | 4 +- .../basemetals/recipes/brass_pickaxe.json | 4 +- .../basemetals/recipes/brass_plate.json | 4 +- .../basemetals/recipes/brass_powder.json | 4 +- .../recipes/brass_pressureplate.json | 4 +- .../assets/basemetals/recipes/brass_rod.json | 3 +- .../basemetals/recipes/brass_scythe.json | 2 +- .../basemetals/recipes/brass_shears.json | 4 +- .../basemetals/recipes/brass_shield.json | 2 +- .../recipes/brass_shield_plate_repair.json | 2 +- .../basemetals/recipes/brass_shovel.json | 4 +- .../assets/basemetals/recipes/brass_slab.json | 4 +- .../recipes/brass_smallblend_blend.json | 4 +- .../basemetals/recipes/brass_smallpowder.json | 4 +- .../basemetals/recipes/brass_stairs.json | 4 +- .../basemetals/recipes/brass_sword.json | 4 +- .../basemetals/recipes/brass_trapdoor.json | 4 +- .../assets/basemetals/recipes/brass_wall.json | 4 +- .../basemetals/recipes/bronze_arrow.json | 4 +- .../assets/basemetals/recipes/bronze_axe.json | 4 +- .../basemetals/recipes/bronze_bars_1.json | 4 +- .../basemetals/recipes/bronze_bars_2.json | 4 +- .../basemetals/recipes/bronze_blend_base.json | 4 +- .../recipes/bronze_blend_smallblend.json | 4 +- .../basemetals/recipes/bronze_block.json | 4 +- .../recipes/bronze_block_ingot.json | 4 +- .../basemetals/recipes/bronze_bolt.json | 4 +- .../basemetals/recipes/bronze_boots.json | 4 +- .../recipes/bronze_boots_plate_repair.json | 2 +- .../assets/basemetals/recipes/bronze_bow.json | 4 +- .../basemetals/recipes/bronze_button.json | 4 +- .../basemetals/recipes/bronze_chestplate.json | 4 +- .../bronze_chestplate_plate_repair.json | 2 +- .../recipes/bronze_crackhammer.json | 4 +- .../basemetals/recipes/bronze_crossbow.json | 4 +- .../basemetals/recipes/bronze_door.json | 4 +- .../basemetals/recipes/bronze_fishingrod.json | 4 +- .../basemetals/recipes/bronze_gear.json | 4 +- .../basemetals/recipes/bronze_helmet.json | 4 +- .../recipes/bronze_helmet_plate_repair.json | 2 +- .../assets/basemetals/recipes/bronze_hoe.json | 4 +- .../basemetals/recipes/bronze_horsearmor.json | 4 +- .../basemetals/recipes/bronze_ingot.json | 4 +- .../basemetals/recipes/bronze_leggings.json | 4 +- .../recipes/bronze_leggings_plate_repair.json | 2 +- .../basemetals/recipes/bronze_lever.json | 4 +- .../basemetals/recipes/bronze_nugget.json | 4 +- .../basemetals/recipes/bronze_pickaxe.json | 4 +- .../basemetals/recipes/bronze_plate.json | 4 +- .../basemetals/recipes/bronze_powder.json | 4 +- .../recipes/bronze_pressureplate.json | 4 +- .../assets/basemetals/recipes/bronze_rod.json | 3 +- .../basemetals/recipes/bronze_scythe.json | 2 +- .../basemetals/recipes/bronze_shears.json | 4 +- .../basemetals/recipes/bronze_shield.json | 2 +- .../recipes/bronze_shield_plate_repair.json | 2 +- .../basemetals/recipes/bronze_shovel.json | 4 +- .../basemetals/recipes/bronze_slab.json | 4 +- .../recipes/bronze_smallblend_blend.json | 4 +- .../recipes/bronze_smallpowder.json | 4 +- .../basemetals/recipes/bronze_stairs.json | 4 +- .../basemetals/recipes/bronze_sword.json | 4 +- .../basemetals/recipes/bronze_trapdoor.json | 4 +- .../basemetals/recipes/bronze_wall.json | 4 +- .../basemetals/recipes/charcoal_block.json | 2 +- .../recipes/charcoal_block_dust.json | 2 +- .../basemetals/recipes/charcoal_ingot.json | 2 +- .../basemetals/recipes/charcoal_nugget.json | 2 +- .../basemetals/recipes/charcoal_powder.json | 2 +- .../recipes/charcoal_smallpowder.json | 2 +- .../basemetals/recipes/coal_block_dust.json | 2 +- .../assets/basemetals/recipes/coal_ingot.json | 2 +- .../basemetals/recipes/coal_nugget.json | 2 +- .../basemetals/recipes/coal_powder.json | 2 +- .../basemetals/recipes/coal_smallpowder.json | 2 +- .../basemetals/recipes/coldiron_arrow.json | 4 +- .../basemetals/recipes/coldiron_axe.json | 4 +- .../basemetals/recipes/coldiron_bars_1.json | 4 +- .../basemetals/recipes/coldiron_bars_2.json | 4 +- .../basemetals/recipes/coldiron_block.json | 4 +- .../recipes/coldiron_block_ingot.json | 4 +- .../basemetals/recipes/coldiron_bolt.json | 4 +- .../basemetals/recipes/coldiron_boots.json | 4 +- .../recipes/coldiron_boots_plate_repair.json | 2 +- .../basemetals/recipes/coldiron_bow.json | 4 +- .../basemetals/recipes/coldiron_button.json | 4 +- .../recipes/coldiron_chestplate.json | 4 +- .../coldiron_chestplate_plate_repair.json | 2 +- .../recipes/coldiron_crackhammer.json | 4 +- .../basemetals/recipes/coldiron_crossbow.json | 4 +- .../basemetals/recipes/coldiron_door.json | 4 +- .../recipes/coldiron_fishingrod.json | 4 +- .../basemetals/recipes/coldiron_gear.json | 4 +- .../basemetals/recipes/coldiron_helmet.json | 4 +- .../recipes/coldiron_helmet_plate_repair.json | 2 +- .../basemetals/recipes/coldiron_hoe.json | 4 +- .../recipes/coldiron_horsearmor.json | 4 +- .../basemetals/recipes/coldiron_ingot.json | 4 +- .../basemetals/recipes/coldiron_leggings.json | 4 +- .../coldiron_leggings_plate_repair.json | 2 +- .../basemetals/recipes/coldiron_lever.json | 4 +- .../basemetals/recipes/coldiron_nugget.json | 4 +- .../basemetals/recipes/coldiron_pickaxe.json | 4 +- .../basemetals/recipes/coldiron_plate.json | 4 +- .../basemetals/recipes/coldiron_powder.json | 4 +- .../recipes/coldiron_pressureplate.json | 4 +- .../basemetals/recipes/coldiron_rod.json | 3 +- .../basemetals/recipes/coldiron_scythe.json | 2 +- .../basemetals/recipes/coldiron_shears.json | 4 +- .../basemetals/recipes/coldiron_shield.json | 2 +- .../recipes/coldiron_shield_plate_repair.json | 2 +- .../basemetals/recipes/coldiron_shovel.json | 4 +- .../basemetals/recipes/coldiron_slab.json | 4 +- .../recipes/coldiron_smallpowder.json | 4 +- .../basemetals/recipes/coldiron_stairs.json | 4 +- .../basemetals/recipes/coldiron_sword.json | 4 +- .../basemetals/recipes/coldiron_trapdoor.json | 4 +- .../basemetals/recipes/coldiron_wall.json | 4 +- .../basemetals/recipes/copper_arrow.json | 4 +- .../assets/basemetals/recipes/copper_axe.json | 4 +- .../basemetals/recipes/copper_bars_1.json | 4 +- .../basemetals/recipes/copper_bars_2.json | 4 +- .../basemetals/recipes/copper_block.json | 4 +- .../recipes/copper_block_ingot.json | 4 +- .../basemetals/recipes/copper_bolt.json | 4 +- .../basemetals/recipes/copper_boots.json | 4 +- .../recipes/copper_boots_plate_repair.json | 2 +- .../assets/basemetals/recipes/copper_bow.json | 4 +- .../basemetals/recipes/copper_button.json | 4 +- .../basemetals/recipes/copper_chestplate.json | 4 +- .../copper_chestplate_plate_repair.json | 2 +- .../recipes/copper_crackhammer.json | 4 +- .../basemetals/recipes/copper_crossbow.json | 4 +- .../basemetals/recipes/copper_door.json | 4 +- .../basemetals/recipes/copper_fishingrod.json | 4 +- .../basemetals/recipes/copper_gear.json | 4 +- .../basemetals/recipes/copper_helmet.json | 4 +- .../recipes/copper_helmet_plate_repair.json | 2 +- .../assets/basemetals/recipes/copper_hoe.json | 4 +- .../basemetals/recipes/copper_horsearmor.json | 4 +- .../basemetals/recipes/copper_ingot.json | 4 +- .../basemetals/recipes/copper_leggings.json | 4 +- .../recipes/copper_leggings_plate_repair.json | 2 +- .../basemetals/recipes/copper_lever.json | 4 +- .../basemetals/recipes/copper_nugget.json | 4 +- .../basemetals/recipes/copper_pickaxe.json | 4 +- .../basemetals/recipes/copper_plate.json | 4 +- .../basemetals/recipes/copper_powder.json | 4 +- .../recipes/copper_pressureplate.json | 4 +- .../assets/basemetals/recipes/copper_rod.json | 3 +- .../basemetals/recipes/copper_scythe.json | 2 +- .../basemetals/recipes/copper_shears.json | 4 +- .../basemetals/recipes/copper_shield.json | 2 +- .../recipes/copper_shield_plate_repair.json | 2 +- .../basemetals/recipes/copper_shovel.json | 4 +- .../basemetals/recipes/copper_slab.json | 4 +- .../recipes/copper_smallpowder.json | 4 +- .../basemetals/recipes/copper_stairs.json | 4 +- .../basemetals/recipes/copper_sword.json | 4 +- .../basemetals/recipes/copper_trapdoor.json | 4 +- .../basemetals/recipes/copper_wall.json | 4 +- .../basemetals/recipes/cupronickel_arrow.json | 4 +- .../basemetals/recipes/cupronickel_axe.json | 4 +- .../recipes/cupronickel_bars_1.json | 4 +- .../recipes/cupronickel_bars_2.json | 4 +- .../recipes/cupronickel_blend_base.json | 4 +- .../recipes/cupronickel_blend_smallblend.json | 4 +- .../basemetals/recipes/cupronickel_block.json | 4 +- .../recipes/cupronickel_block_ingot.json | 4 +- .../basemetals/recipes/cupronickel_bolt.json | 4 +- .../basemetals/recipes/cupronickel_boots.json | 4 +- .../cupronickel_boots_plate_repair.json | 2 +- .../basemetals/recipes/cupronickel_bow.json | 4 +- .../recipes/cupronickel_button.json | 4 +- .../recipes/cupronickel_chestplate.json | 4 +- .../cupronickel_chestplate_plate_repair.json | 2 +- .../recipes/cupronickel_crackhammer.json | 4 +- .../recipes/cupronickel_crossbow.json | 4 +- .../basemetals/recipes/cupronickel_door.json | 4 +- .../recipes/cupronickel_fishingrod.json | 4 +- .../basemetals/recipes/cupronickel_gear.json | 4 +- .../recipes/cupronickel_helmet.json | 4 +- .../cupronickel_helmet_plate_repair.json | 2 +- .../basemetals/recipes/cupronickel_hoe.json | 4 +- .../recipes/cupronickel_horsearmor.json | 4 +- .../basemetals/recipes/cupronickel_ingot.json | 4 +- .../recipes/cupronickel_leggings.json | 4 +- .../cupronickel_leggings_plate_repair.json | 2 +- .../basemetals/recipes/cupronickel_lever.json | 4 +- .../recipes/cupronickel_nugget.json | 4 +- .../recipes/cupronickel_pickaxe.json | 4 +- .../basemetals/recipes/cupronickel_plate.json | 4 +- .../recipes/cupronickel_powder.json | 4 +- .../recipes/cupronickel_pressureplate.json | 4 +- .../basemetals/recipes/cupronickel_rod.json | 3 +- .../recipes/cupronickel_scythe.json | 2 +- .../recipes/cupronickel_shears.json | 4 +- .../recipes/cupronickel_shield.json | 2 +- .../cupronickel_shield_plate_repair.json | 2 +- .../recipes/cupronickel_shovel.json | 4 +- .../basemetals/recipes/cupronickel_slab.json | 4 +- .../recipes/cupronickel_smallblend_blend.json | 4 +- .../recipes/cupronickel_smallpowder.json | 4 +- .../recipes/cupronickel_stairs.json | 4 +- .../basemetals/recipes/cupronickel_sword.json | 4 +- .../recipes/cupronickel_trapdoor.json | 4 +- .../basemetals/recipes/cupronickel_wall.json | 4 +- .../basemetals/recipes/detector_rail.json | 2 +- .../basemetals/recipes/diamond_arrow.json | 2 +- .../basemetals/recipes/diamond_bars_1.json | 2 +- .../basemetals/recipes/diamond_bars_2.json | 2 +- .../basemetals/recipes/diamond_bolt.json | 2 +- .../recipes/diamond_boots_plate_repair.json | 2 +- .../basemetals/recipes/diamond_bow.json | 2 +- .../basemetals/recipes/diamond_button.json | 2 +- .../diamond_chestplate_plate_repair.json | 2 +- .../recipes/diamond_crackhammer.json | 2 +- .../basemetals/recipes/diamond_crossbow.json | 2 +- .../basemetals/recipes/diamond_door.json | 2 +- .../recipes/diamond_fishingrod.json | 2 +- .../basemetals/recipes/diamond_gear.json | 2 +- .../recipes/diamond_helmet_plate_repair.json | 2 +- .../diamond_leggings_plate_repair.json | 2 +- .../basemetals/recipes/diamond_lever.json | 2 +- .../basemetals/recipes/diamond_powder.json | 2 +- .../recipes/diamond_pressureplate.json | 2 +- .../basemetals/recipes/diamond_rod.json | 3 +- .../basemetals/recipes/diamond_scythe.json | 2 +- .../basemetals/recipes/diamond_shears.json | 2 +- .../basemetals/recipes/diamond_shield.json | 2 +- .../recipes/diamond_shield_plate_repair.json | 2 +- .../basemetals/recipes/diamond_slab.json | 2 +- .../recipes/diamond_smallpowder.json | 2 +- .../basemetals/recipes/diamond_stairs.json | 2 +- .../basemetals/recipes/diamond_trapdoor.json | 2 +- .../basemetals/recipes/diamond_wall.json | 2 +- .../basemetals/recipes/electrum_arrow.json | 4 +- .../basemetals/recipes/electrum_axe.json | 4 +- .../basemetals/recipes/electrum_bars_1.json | 4 +- .../basemetals/recipes/electrum_bars_2.json | 4 +- .../recipes/electrum_blend_base.json | 4 +- .../recipes/electrum_blend_smallblend.json | 4 +- .../basemetals/recipes/electrum_block.json | 4 +- .../recipes/electrum_block_ingot.json | 4 +- .../basemetals/recipes/electrum_bolt.json | 4 +- .../basemetals/recipes/electrum_boots.json | 4 +- .../recipes/electrum_boots_plate_repair.json | 2 +- .../basemetals/recipes/electrum_bow.json | 4 +- .../basemetals/recipes/electrum_button.json | 4 +- .../recipes/electrum_chestplate.json | 4 +- .../electrum_chestplate_plate_repair.json | 2 +- .../recipes/electrum_crackhammer.json | 4 +- .../basemetals/recipes/electrum_crossbow.json | 4 +- .../basemetals/recipes/electrum_door.json | 4 +- .../recipes/electrum_fishingrod.json | 4 +- .../basemetals/recipes/electrum_gear.json | 4 +- .../basemetals/recipes/electrum_helmet.json | 4 +- .../recipes/electrum_helmet_plate_repair.json | 2 +- .../basemetals/recipes/electrum_hoe.json | 4 +- .../recipes/electrum_horsearmor.json | 4 +- .../basemetals/recipes/electrum_ingot.json | 4 +- .../basemetals/recipes/electrum_leggings.json | 4 +- .../electrum_leggings_plate_repair.json | 2 +- .../basemetals/recipes/electrum_lever.json | 4 +- .../basemetals/recipes/electrum_nugget.json | 4 +- .../basemetals/recipes/electrum_pickaxe.json | 4 +- .../basemetals/recipes/electrum_plate.json | 4 +- .../basemetals/recipes/electrum_powder.json | 4 +- .../recipes/electrum_pressureplate.json | 4 +- .../basemetals/recipes/electrum_rod.json | 3 +- .../basemetals/recipes/electrum_scythe.json | 2 +- .../basemetals/recipes/electrum_shears.json | 4 +- .../basemetals/recipes/electrum_shield.json | 2 +- .../recipes/electrum_shield_plate_repair.json | 2 +- .../basemetals/recipes/electrum_shovel.json | 4 +- .../basemetals/recipes/electrum_slab.json | 4 +- .../recipes/electrum_smallblend_blend.json | 4 +- .../recipes/electrum_smallpowder.json | 4 +- .../basemetals/recipes/electrum_stairs.json | 4 +- .../basemetals/recipes/electrum_sword.json | 4 +- .../basemetals/recipes/electrum_trapdoor.json | 4 +- .../basemetals/recipes/electrum_wall.json | 4 +- .../basemetals/recipes/emerald_arrow.json | 2 +- .../basemetals/recipes/emerald_axe.json | 2 +- .../basemetals/recipes/emerald_bars_1.json | 2 +- .../basemetals/recipes/emerald_bars_2.json | 2 +- .../basemetals/recipes/emerald_bolt.json | 2 +- .../basemetals/recipes/emerald_boots.json | 2 +- .../recipes/emerald_boots_plate_repair.json | 2 +- .../basemetals/recipes/emerald_bow.json | 2 +- .../basemetals/recipes/emerald_button.json | 2 +- .../recipes/emerald_chestplate.json | 2 +- .../emerald_chestplate_plate_repair.json | 2 +- .../recipes/emerald_crackhammer.json | 2 +- .../basemetals/recipes/emerald_crossbow.json | 2 +- .../basemetals/recipes/emerald_door.json | 2 +- .../recipes/emerald_fishingrod.json | 2 +- .../basemetals/recipes/emerald_gear.json | 2 +- .../basemetals/recipes/emerald_helmet.json | 2 +- .../recipes/emerald_helmet_plate_repair.json | 2 +- .../basemetals/recipes/emerald_hoe.json | 2 +- .../recipes/emerald_horsearmor.json | 2 +- .../basemetals/recipes/emerald_leggings.json | 2 +- .../emerald_leggings_plate_repair.json | 2 +- .../basemetals/recipes/emerald_lever.json | 2 +- .../basemetals/recipes/emerald_pickaxe.json | 2 +- .../basemetals/recipes/emerald_powder.json | 2 +- .../recipes/emerald_pressureplate.json | 2 +- .../basemetals/recipes/emerald_rod.json | 3 +- .../basemetals/recipes/emerald_scythe.json | 2 +- .../basemetals/recipes/emerald_shears.json | 2 +- .../basemetals/recipes/emerald_shield.json | 2 +- .../recipes/emerald_shield_plate_repair.json | 2 +- .../basemetals/recipes/emerald_shovel.json | 2 +- .../basemetals/recipes/emerald_slab.json | 2 +- .../recipes/emerald_smallpowder.json | 2 +- .../basemetals/recipes/emerald_stairs.json | 2 +- .../basemetals/recipes/emerald_sword.json | 2 +- .../basemetals/recipes/emerald_trapdoor.json | 2 +- .../basemetals/recipes/emerald_wall.json | 2 +- .../basemetals/recipes/flint_and_steel.json | 2 +- .../assets/basemetals/recipes/gold_arrow.json | 2 +- .../basemetals/recipes/gold_bars_1.json | 2 +- .../basemetals/recipes/gold_bars_2.json | 2 +- .../assets/basemetals/recipes/gold_bolt.json | 2 +- .../recipes/gold_boots_plate_repair.json | 2 +- .../assets/basemetals/recipes/gold_bow.json | 2 +- .../basemetals/recipes/gold_button.json | 2 +- .../recipes/gold_chestplate_plate_repair.json | 2 +- .../basemetals/recipes/gold_crackhammer.json | 2 +- .../basemetals/recipes/gold_crossbow.json | 2 +- .../assets/basemetals/recipes/gold_door.json | 2 +- .../basemetals/recipes/gold_fishingrod.json | 2 +- .../assets/basemetals/recipes/gold_gear.json | 2 +- .../recipes/gold_helmet_plate_repair.json | 2 +- .../recipes/gold_leggings_plate_repair.json | 2 +- .../assets/basemetals/recipes/gold_lever.json | 2 +- .../assets/basemetals/recipes/gold_plate.json | 2 +- .../basemetals/recipes/gold_powder.json | 2 +- .../assets/basemetals/recipes/gold_rod.json | 3 +- .../basemetals/recipes/gold_scythe.json | 2 +- .../basemetals/recipes/gold_shears.json | 2 +- .../basemetals/recipes/gold_shield.json | 2 +- .../recipes/gold_shield_plate_repair.json | 2 +- .../assets/basemetals/recipes/gold_slab.json | 2 +- .../basemetals/recipes/gold_smallpowder.json | 2 +- .../basemetals/recipes/gold_stairs.json | 2 +- .../basemetals/recipes/gold_trapdoor.json | 2 +- .../assets/basemetals/recipes/gold_wall.json | 2 +- .../basemetals/recipes/human_detector.json | 2 +- .../basemetals/recipes/invar_arrow.json | 4 +- .../assets/basemetals/recipes/invar_axe.json | 4 +- .../basemetals/recipes/invar_bars_1.json | 4 +- .../basemetals/recipes/invar_bars_2.json | 4 +- .../basemetals/recipes/invar_blend_base.json | 4 +- .../recipes/invar_blend_smallblend.json | 4 +- .../basemetals/recipes/invar_block.json | 4 +- .../basemetals/recipes/invar_block_ingot.json | 4 +- .../assets/basemetals/recipes/invar_bolt.json | 4 +- .../basemetals/recipes/invar_boots.json | 4 +- .../assets/basemetals/recipes/invar_bow.json | 4 +- .../basemetals/recipes/invar_button.json | 4 +- .../basemetals/recipes/invar_chestplate.json | 4 +- .../basemetals/recipes/invar_crackhammer.json | 4 +- .../basemetals/recipes/invar_crossbow.json | 4 +- .../assets/basemetals/recipes/invar_door.json | 4 +- .../basemetals/recipes/invar_fishingrod.json | 4 +- .../assets/basemetals/recipes/invar_gear.json | 4 +- .../basemetals/recipes/invar_helmet.json | 4 +- .../assets/basemetals/recipes/invar_hoe.json | 4 +- .../basemetals/recipes/invar_horsearmor.json | 4 +- .../basemetals/recipes/invar_ingot.json | 4 +- .../basemetals/recipes/invar_leggings.json | 4 +- .../basemetals/recipes/invar_lever.json | 4 +- .../basemetals/recipes/invar_nugget.json | 4 +- .../basemetals/recipes/invar_pickaxe.json | 4 +- .../basemetals/recipes/invar_plate.json | 4 +- .../basemetals/recipes/invar_powder.json | 4 +- .../recipes/invar_pressureplate.json | 4 +- .../assets/basemetals/recipes/invar_rod.json | 3 +- .../basemetals/recipes/invar_scythe.json | 2 +- .../basemetals/recipes/invar_shears.json | 4 +- .../basemetals/recipes/invar_shield.json | 2 +- .../basemetals/recipes/invar_shovel.json | 4 +- .../assets/basemetals/recipes/invar_slab.json | 4 +- .../recipes/invar_smallblend_blend.json | 4 +- .../basemetals/recipes/invar_smallpowder.json | 4 +- .../basemetals/recipes/invar_stairs.json | 4 +- .../basemetals/recipes/invar_sword.json | 4 +- .../basemetals/recipes/invar_trapdoor.json | 4 +- .../assets/basemetals/recipes/invar_wall.json | 4 +- .../assets/basemetals/recipes/iron_arrow.json | 2 +- .../basemetals/recipes/iron_bars_2.json | 2 +- .../assets/basemetals/recipes/iron_bolt.json | 2 +- .../recipes/iron_boots_plate_repair.json | 2 +- .../assets/basemetals/recipes/iron_bow.json | 2 +- .../basemetals/recipes/iron_button.json | 2 +- .../recipes/iron_chestplate_plate_repair.json | 2 +- .../basemetals/recipes/iron_crackhammer.json | 2 +- .../basemetals/recipes/iron_crossbow.json | 2 +- .../basemetals/recipes/iron_fishingrod.json | 2 +- .../assets/basemetals/recipes/iron_gear.json | 2 +- .../recipes/iron_helmet_plate_repair.json | 2 +- .../recipes/iron_leggings_plate_repair.json | 2 +- .../assets/basemetals/recipes/iron_lever.json | 2 +- .../assets/basemetals/recipes/iron_plate.json | 2 +- .../basemetals/recipes/iron_powder.json | 2 +- .../assets/basemetals/recipes/iron_rod.json | 3 +- .../basemetals/recipes/iron_scythe.json | 2 +- .../basemetals/recipes/iron_shield.json | 2 +- .../recipes/iron_shield_plate_repair.json | 2 +- .../assets/basemetals/recipes/iron_slab.json | 2 +- .../basemetals/recipes/iron_smallpowder.json | 2 +- .../basemetals/recipes/iron_stairs.json | 2 +- .../assets/basemetals/recipes/iron_wall.json | 2 +- .../assets/basemetals/recipes/lead_arrow.json | 4 +- .../assets/basemetals/recipes/lead_axe.json | 4 +- .../basemetals/recipes/lead_bars_1.json | 4 +- .../basemetals/recipes/lead_bars_2.json | 4 +- .../assets/basemetals/recipes/lead_block.json | 4 +- .../basemetals/recipes/lead_block_ingot.json | 4 +- .../assets/basemetals/recipes/lead_bolt.json | 4 +- .../assets/basemetals/recipes/lead_boots.json | 4 +- .../recipes/lead_boots_plate_repair.json | 2 +- .../assets/basemetals/recipes/lead_bow.json | 4 +- .../basemetals/recipes/lead_button.json | 4 +- .../basemetals/recipes/lead_chestplate.json | 4 +- .../recipes/lead_chestplate_plate_repair.json | 2 +- .../basemetals/recipes/lead_crackhammer.json | 4 +- .../basemetals/recipes/lead_crossbow.json | 4 +- .../assets/basemetals/recipes/lead_door.json | 4 +- .../basemetals/recipes/lead_fishingrod.json | 4 +- .../assets/basemetals/recipes/lead_gear.json | 4 +- .../basemetals/recipes/lead_helmet.json | 4 +- .../recipes/lead_helmet_plate_repair.json | 2 +- .../assets/basemetals/recipes/lead_hoe.json | 4 +- .../basemetals/recipes/lead_horsearmor.json | 4 +- .../assets/basemetals/recipes/lead_ingot.json | 4 +- .../basemetals/recipes/lead_leggings.json | 4 +- .../recipes/lead_leggings_plate_repair.json | 2 +- .../assets/basemetals/recipes/lead_lever.json | 4 +- .../basemetals/recipes/lead_nugget.json | 4 +- .../basemetals/recipes/lead_pickaxe.json | 4 +- .../assets/basemetals/recipes/lead_plate.json | 4 +- .../basemetals/recipes/lead_powder.json | 4 +- .../recipes/lead_pressureplate.json | 4 +- .../assets/basemetals/recipes/lead_rod.json | 3 +- .../basemetals/recipes/lead_scythe.json | 2 +- .../basemetals/recipes/lead_shears.json | 4 +- .../basemetals/recipes/lead_shield.json | 2 +- .../recipes/lead_shield_plate_repair.json | 2 +- .../basemetals/recipes/lead_shovel.json | 4 +- .../assets/basemetals/recipes/lead_slab.json | 4 +- .../basemetals/recipes/lead_smallpowder.json | 4 +- .../basemetals/recipes/lead_stairs.json | 4 +- .../assets/basemetals/recipes/lead_sword.json | 4 +- .../basemetals/recipes/lead_trapdoor.json | 4 +- .../assets/basemetals/recipes/lead_wall.json | 4 +- .../assets/basemetals/recipes/minecart.json | 2 +- .../basemetals/recipes/mithril_arrow.json | 4 +- .../basemetals/recipes/mithril_axe.json | 4 +- .../basemetals/recipes/mithril_bars_1.json | 4 +- .../basemetals/recipes/mithril_bars_2.json | 4 +- .../recipes/mithril_blend_base.json | 2 +- .../recipes/mithril_blend_base_alternate.json | 2 +- .../recipes/mithril_blend_smallblend.json | 4 +- .../basemetals/recipes/mithril_block.json | 4 +- .../recipes/mithril_block_ingot.json | 4 +- .../basemetals/recipes/mithril_bolt.json | 4 +- .../basemetals/recipes/mithril_boots.json | 4 +- .../basemetals/recipes/mithril_bow.json | 4 +- .../basemetals/recipes/mithril_button.json | 4 +- .../recipes/mithril_chestplate.json | 4 +- .../recipes/mithril_crackhammer.json | 4 +- .../basemetals/recipes/mithril_crossbow.json | 4 +- .../basemetals/recipes/mithril_door.json | 4 +- .../recipes/mithril_fishingrod.json | 4 +- .../basemetals/recipes/mithril_gear.json | 4 +- .../basemetals/recipes/mithril_helmet.json | 4 +- .../basemetals/recipes/mithril_hoe.json | 4 +- .../recipes/mithril_horsearmor.json | 4 +- .../basemetals/recipes/mithril_ingot.json | 4 +- .../basemetals/recipes/mithril_leggings.json | 4 +- .../basemetals/recipes/mithril_lever.json | 4 +- .../basemetals/recipes/mithril_nugget.json | 4 +- .../basemetals/recipes/mithril_pickaxe.json | 4 +- .../basemetals/recipes/mithril_plate.json | 4 +- .../basemetals/recipes/mithril_powder.json | 4 +- .../recipes/mithril_pressureplate.json | 4 +- .../basemetals/recipes/mithril_rod.json | 3 +- .../basemetals/recipes/mithril_scythe.json | 2 +- .../basemetals/recipes/mithril_shears.json | 4 +- .../basemetals/recipes/mithril_shield.json | 2 +- .../basemetals/recipes/mithril_shovel.json | 4 +- .../basemetals/recipes/mithril_slab.json | 4 +- .../recipes/mithril_smallblend_blend.json | 4 +- .../recipes/mithril_smallpowder.json | 4 +- .../basemetals/recipes/mithril_stairs.json | 4 +- .../basemetals/recipes/mithril_sword.json | 4 +- .../basemetals/recipes/mithril_trapdoor.json | 4 +- .../basemetals/recipes/mithril_wall.json | 4 +- .../basemetals/recipes/nickel_arrow.json | 4 +- .../assets/basemetals/recipes/nickel_axe.json | 4 +- .../basemetals/recipes/nickel_bars_1.json | 4 +- .../basemetals/recipes/nickel_bars_2.json | 4 +- .../basemetals/recipes/nickel_block.json | 4 +- .../recipes/nickel_block_ingot.json | 4 +- .../basemetals/recipes/nickel_bolt.json | 4 +- .../basemetals/recipes/nickel_boots.json | 4 +- .../recipes/nickel_boots_plate_repair.json | 2 +- .../assets/basemetals/recipes/nickel_bow.json | 4 +- .../basemetals/recipes/nickel_button.json | 4 +- .../basemetals/recipes/nickel_chestplate.json | 4 +- .../nickel_chestplate_plate_repair.json | 2 +- .../recipes/nickel_crackhammer.json | 4 +- .../basemetals/recipes/nickel_crossbow.json | 4 +- .../basemetals/recipes/nickel_door.json | 4 +- .../basemetals/recipes/nickel_fishingrod.json | 4 +- .../basemetals/recipes/nickel_gear.json | 4 +- .../basemetals/recipes/nickel_helmet.json | 4 +- .../recipes/nickel_helmet_plate_repair.json | 2 +- .../assets/basemetals/recipes/nickel_hoe.json | 4 +- .../basemetals/recipes/nickel_horsearmor.json | 4 +- .../basemetals/recipes/nickel_ingot.json | 4 +- .../basemetals/recipes/nickel_leggings.json | 4 +- .../recipes/nickel_leggings_plate_repair.json | 2 +- .../basemetals/recipes/nickel_lever.json | 4 +- .../basemetals/recipes/nickel_nugget.json | 4 +- .../basemetals/recipes/nickel_pickaxe.json | 4 +- .../basemetals/recipes/nickel_plate.json | 4 +- .../basemetals/recipes/nickel_powder.json | 4 +- .../recipes/nickel_pressureplate.json | 4 +- .../assets/basemetals/recipes/nickel_rod.json | 3 +- .../basemetals/recipes/nickel_scythe.json | 2 +- .../basemetals/recipes/nickel_shears.json | 4 +- .../basemetals/recipes/nickel_shield.json | 2 +- .../recipes/nickel_shield_plate_repair.json | 2 +- .../basemetals/recipes/nickel_shovel.json | 4 +- .../basemetals/recipes/nickel_slab.json | 4 +- .../recipes/nickel_smallpowder.json | 4 +- .../basemetals/recipes/nickel_stairs.json | 4 +- .../basemetals/recipes/nickel_sword.json | 4 +- .../basemetals/recipes/nickel_trapdoor.json | 4 +- .../basemetals/recipes/nickel_wall.json | 4 +- .../basemetals/recipes/obsidian_arrow.json | 2 +- .../basemetals/recipes/obsidian_axe.json | 2 +- .../basemetals/recipes/obsidian_bars_1.json | 2 +- .../basemetals/recipes/obsidian_bars_2.json | 2 +- .../basemetals/recipes/obsidian_block.json | 2 +- .../basemetals/recipes/obsidian_bolt.json | 2 +- .../basemetals/recipes/obsidian_boots.json | 2 +- .../basemetals/recipes/obsidian_bow.json | 2 +- .../basemetals/recipes/obsidian_button.json | 2 +- .../recipes/obsidian_chestplate.json | 2 +- .../recipes/obsidian_crackhammer.json | 2 +- .../basemetals/recipes/obsidian_crossbow.json | 2 +- .../basemetals/recipes/obsidian_door.json | 2 +- .../recipes/obsidian_fishingrod.json | 2 +- .../basemetals/recipes/obsidian_gear.json | 2 +- .../basemetals/recipes/obsidian_helmet.json | 2 +- .../basemetals/recipes/obsidian_hoe.json | 2 +- .../recipes/obsidian_horsearmor.json | 2 +- .../basemetals/recipes/obsidian_ingot.json | 2 +- .../basemetals/recipes/obsidian_leggings.json | 2 +- .../basemetals/recipes/obsidian_lever.json | 2 +- .../basemetals/recipes/obsidian_nugget.json | 2 +- .../basemetals/recipes/obsidian_pickaxe.json | 2 +- .../basemetals/recipes/obsidian_powder.json | 2 +- .../recipes/obsidian_pressureplate.json | 2 +- .../basemetals/recipes/obsidian_rod.json | 3 +- .../basemetals/recipes/obsidian_scythe.json | 2 +- .../basemetals/recipes/obsidian_shears.json | 2 +- .../basemetals/recipes/obsidian_shield.json | 2 +- .../basemetals/recipes/obsidian_shovel.json | 2 +- .../basemetals/recipes/obsidian_slab.json | 2 +- .../recipes/obsidian_smallpowder.json | 2 +- .../basemetals/recipes/obsidian_stairs.json | 2 +- .../basemetals/recipes/obsidian_sword.json | 2 +- .../basemetals/recipes/obsidian_trapdoor.json | 2 +- .../basemetals/recipes/obsidian_wall.json | 2 +- .../basemetals/recipes/pewter_arrow.json | 4 +- .../assets/basemetals/recipes/pewter_axe.json | 4 +- .../basemetals/recipes/pewter_bars_1.json | 4 +- .../basemetals/recipes/pewter_bars_2.json | 4 +- .../basemetals/recipes/pewter_blend_base.json | 4 +- .../recipes/pewter_blend_smallblend.json | 4 +- .../basemetals/recipes/pewter_block.json | 4 +- .../recipes/pewter_block_ingot.json | 4 +- .../basemetals/recipes/pewter_bolt.json | 4 +- .../basemetals/recipes/pewter_boots.json | 4 +- .../recipes/pewter_boots_plate_repair.json | 2 +- .../assets/basemetals/recipes/pewter_bow.json | 4 +- .../basemetals/recipes/pewter_button.json | 4 +- .../basemetals/recipes/pewter_chestplate.json | 4 +- .../pewter_chestplate_plate_repair.json | 2 +- .../recipes/pewter_crackhammer.json | 4 +- .../basemetals/recipes/pewter_crossbow.json | 4 +- .../basemetals/recipes/pewter_door.json | 4 +- .../basemetals/recipes/pewter_fishingrod.json | 4 +- .../basemetals/recipes/pewter_gear.json | 4 +- .../basemetals/recipes/pewter_helmet.json | 4 +- .../recipes/pewter_helmet_plate_repair.json | 2 +- .../assets/basemetals/recipes/pewter_hoe.json | 4 +- .../basemetals/recipes/pewter_horsearmor.json | 4 +- .../basemetals/recipes/pewter_ingot.json | 4 +- .../basemetals/recipes/pewter_leggings.json | 4 +- .../recipes/pewter_leggings_plate_repair.json | 2 +- .../basemetals/recipes/pewter_lever.json | 4 +- .../basemetals/recipes/pewter_nugget.json | 4 +- .../basemetals/recipes/pewter_pickaxe.json | 4 +- .../basemetals/recipes/pewter_plate.json | 4 +- .../basemetals/recipes/pewter_powder.json | 4 +- .../recipes/pewter_pressureplate.json | 4 +- .../assets/basemetals/recipes/pewter_rod.json | 3 +- .../basemetals/recipes/pewter_scythe.json | 2 +- .../basemetals/recipes/pewter_shears.json | 4 +- .../basemetals/recipes/pewter_shield.json | 2 +- .../recipes/pewter_shield_plate_repair.json | 2 +- .../basemetals/recipes/pewter_shovel.json | 4 +- .../basemetals/recipes/pewter_slab.json | 4 +- .../recipes/pewter_smallblend_blend.json | 4 +- .../recipes/pewter_smallpowder.json | 4 +- .../basemetals/recipes/pewter_stairs.json | 4 +- .../basemetals/recipes/pewter_sword.json | 4 +- .../basemetals/recipes/pewter_trapdoor.json | 4 +- .../basemetals/recipes/pewter_wall.json | 4 +- .../assets/basemetals/recipes/piston.json | 2 +- .../basemetals/recipes/platinum_arrow.json | 4 +- .../basemetals/recipes/platinum_axe.json | 4 +- .../basemetals/recipes/platinum_bars_1.json | 4 +- .../basemetals/recipes/platinum_bars_2.json | 4 +- .../basemetals/recipes/platinum_block.json | 4 +- .../recipes/platinum_block_ingot.json | 4 +- .../basemetals/recipes/platinum_bolt.json | 4 +- .../basemetals/recipes/platinum_boots.json | 4 +- .../recipes/platinum_boots_plate_repair.json | 2 +- .../basemetals/recipes/platinum_bow.json | 4 +- .../basemetals/recipes/platinum_button.json | 4 +- .../recipes/platinum_chestplate.json | 4 +- .../platinum_chestplate_plate_repair.json | 2 +- .../recipes/platinum_crackhammer.json | 4 +- .../basemetals/recipes/platinum_crossbow.json | 4 +- .../basemetals/recipes/platinum_door.json | 4 +- .../recipes/platinum_fishingrod.json | 4 +- .../basemetals/recipes/platinum_gear.json | 4 +- .../basemetals/recipes/platinum_helmet.json | 4 +- .../recipes/platinum_helmet_plate_repair.json | 2 +- .../basemetals/recipes/platinum_hoe.json | 4 +- .../recipes/platinum_horsearmor.json | 4 +- .../basemetals/recipes/platinum_ingot.json | 4 +- .../basemetals/recipes/platinum_leggings.json | 4 +- .../platinum_leggings_plate_repair.json | 2 +- .../basemetals/recipes/platinum_lever.json | 4 +- .../basemetals/recipes/platinum_nugget.json | 4 +- .../basemetals/recipes/platinum_pickaxe.json | 4 +- .../basemetals/recipes/platinum_plate.json | 4 +- .../basemetals/recipes/platinum_powder.json | 4 +- .../recipes/platinum_pressureplate.json | 4 +- .../basemetals/recipes/platinum_rod.json | 3 +- .../basemetals/recipes/platinum_scythe.json | 2 +- .../basemetals/recipes/platinum_shears.json | 4 +- .../basemetals/recipes/platinum_shield.json | 2 +- .../recipes/platinum_shield_plate_repair.json | 2 +- .../basemetals/recipes/platinum_shovel.json | 4 +- .../basemetals/recipes/platinum_slab.json | 4 +- .../recipes/platinum_smallpowder.json | 4 +- .../basemetals/recipes/platinum_stairs.json | 4 +- .../basemetals/recipes/platinum_sword.json | 4 +- .../basemetals/recipes/platinum_trapdoor.json | 4 +- .../basemetals/recipes/platinum_wall.json | 4 +- .../basemetals/recipes/quartz_arrow.json | 2 +- .../assets/basemetals/recipes/quartz_axe.json | 2 +- .../basemetals/recipes/quartz_bars_1.json | 2 +- .../basemetals/recipes/quartz_bars_2.json | 2 +- .../basemetals/recipes/quartz_bolt.json | 2 +- .../basemetals/recipes/quartz_boots.json | 2 +- .../assets/basemetals/recipes/quartz_bow.json | 2 +- .../basemetals/recipes/quartz_button.json | 2 +- .../basemetals/recipes/quartz_chestplate.json | 2 +- .../recipes/quartz_crackhammer.json | 2 +- .../basemetals/recipes/quartz_crossbow.json | 2 +- .../basemetals/recipes/quartz_door.json | 2 +- .../basemetals/recipes/quartz_fishingrod.json | 2 +- .../basemetals/recipes/quartz_gear.json | 2 +- .../basemetals/recipes/quartz_helmet.json | 2 +- .../assets/basemetals/recipes/quartz_hoe.json | 2 +- .../basemetals/recipes/quartz_horsearmor.json | 2 +- .../basemetals/recipes/quartz_ingot.json | 2 +- .../basemetals/recipes/quartz_leggings.json | 2 +- .../basemetals/recipes/quartz_lever.json | 2 +- .../basemetals/recipes/quartz_nugget.json | 2 +- .../basemetals/recipes/quartz_pickaxe.json | 2 +- .../basemetals/recipes/quartz_powder.json | 2 +- .../recipes/quartz_pressureplate.json | 2 +- .../assets/basemetals/recipes/quartz_rod.json | 3 +- .../basemetals/recipes/quartz_scythe.json | 2 +- .../basemetals/recipes/quartz_shears.json | 2 +- .../basemetals/recipes/quartz_shield.json | 2 +- .../basemetals/recipes/quartz_shovel.json | 2 +- .../recipes/quartz_smallpowder.json | 2 +- .../basemetals/recipes/quartz_sword.json | 2 +- .../basemetals/recipes/quartz_trapdoor.json | 2 +- .../basemetals/recipes/quartz_wall.json | 2 +- .../assets/basemetals/recipes/rail.json | 2 +- .../basemetals/recipes/redstone_powder.json | 2 +- .../recipes/redstone_smallpowder.json | 2 +- .../basemetals/recipes/silver_arrow.json | 4 +- .../assets/basemetals/recipes/silver_axe.json | 4 +- .../basemetals/recipes/silver_bars_1.json | 4 +- .../basemetals/recipes/silver_bars_2.json | 4 +- .../basemetals/recipes/silver_block.json | 4 +- .../recipes/silver_block_ingot.json | 4 +- .../basemetals/recipes/silver_bolt.json | 4 +- .../basemetals/recipes/silver_boots.json | 4 +- .../recipes/silver_boots_plate_repair.json | 2 +- .../assets/basemetals/recipes/silver_bow.json | 4 +- .../basemetals/recipes/silver_button.json | 4 +- .../basemetals/recipes/silver_chestplate.json | 4 +- .../silver_chestplate_plate_repair.json | 2 +- .../recipes/silver_crackhammer.json | 4 +- .../basemetals/recipes/silver_crossbow.json | 4 +- .../basemetals/recipes/silver_door.json | 4 +- .../basemetals/recipes/silver_fishingrod.json | 4 +- .../basemetals/recipes/silver_gear.json | 4 +- .../basemetals/recipes/silver_helmet.json | 4 +- .../recipes/silver_helmet_plate_repair.json | 2 +- .../assets/basemetals/recipes/silver_hoe.json | 4 +- .../basemetals/recipes/silver_horsearmor.json | 4 +- .../basemetals/recipes/silver_ingot.json | 4 +- .../basemetals/recipes/silver_leggings.json | 4 +- .../recipes/silver_leggings_plate_repair.json | 2 +- .../basemetals/recipes/silver_lever.json | 4 +- .../basemetals/recipes/silver_nugget.json | 4 +- .../basemetals/recipes/silver_pickaxe.json | 4 +- .../basemetals/recipes/silver_plate.json | 4 +- .../basemetals/recipes/silver_powder.json | 4 +- .../recipes/silver_pressureplate.json | 4 +- .../assets/basemetals/recipes/silver_rod.json | 3 +- .../basemetals/recipes/silver_scythe.json | 2 +- .../basemetals/recipes/silver_shears.json | 4 +- .../basemetals/recipes/silver_shield.json | 2 +- .../recipes/silver_shield_plate_repair.json | 2 +- .../basemetals/recipes/silver_shovel.json | 4 +- .../basemetals/recipes/silver_slab.json | 4 +- .../recipes/silver_smallpowder.json | 4 +- .../basemetals/recipes/silver_stairs.json | 4 +- .../basemetals/recipes/silver_sword.json | 4 +- .../basemetals/recipes/silver_trapdoor.json | 4 +- .../basemetals/recipes/silver_wall.json | 4 +- .../basemetals/recipes/starsteel_arrow.json | 4 +- .../basemetals/recipes/starsteel_axe.json | 4 +- .../basemetals/recipes/starsteel_bars_1.json | 4 +- .../basemetals/recipes/starsteel_bars_2.json | 4 +- .../basemetals/recipes/starsteel_block.json | 4 +- .../recipes/starsteel_block_ingot.json | 4 +- .../basemetals/recipes/starsteel_bolt.json | 4 +- .../basemetals/recipes/starsteel_boots.json | 4 +- .../recipes/starsteel_boots_plate_repair.json | 2 +- .../basemetals/recipes/starsteel_bow.json | 4 +- .../basemetals/recipes/starsteel_button.json | 4 +- .../recipes/starsteel_chestplate.json | 4 +- .../starsteel_chestplate_plate_repair.json | 2 +- .../recipes/starsteel_crackhammer.json | 4 +- .../recipes/starsteel_crossbow.json | 4 +- .../basemetals/recipes/starsteel_door.json | 4 +- .../recipes/starsteel_fishingrod.json | 4 +- .../basemetals/recipes/starsteel_gear.json | 4 +- .../basemetals/recipes/starsteel_helmet.json | 4 +- .../starsteel_helmet_plate_repair.json | 2 +- .../basemetals/recipes/starsteel_hoe.json | 4 +- .../recipes/starsteel_horsearmor.json | 4 +- .../basemetals/recipes/starsteel_ingot.json | 4 +- .../recipes/starsteel_leggings.json | 4 +- .../starsteel_leggings_plate_repair.json | 2 +- .../basemetals/recipes/starsteel_lever.json | 4 +- .../basemetals/recipes/starsteel_nugget.json | 4 +- .../basemetals/recipes/starsteel_pickaxe.json | 4 +- .../basemetals/recipes/starsteel_plate.json | 4 +- .../basemetals/recipes/starsteel_powder.json | 4 +- .../recipes/starsteel_pressureplate.json | 4 +- .../basemetals/recipes/starsteel_rod.json | 3 +- .../basemetals/recipes/starsteel_scythe.json | 2 +- .../basemetals/recipes/starsteel_shears.json | 4 +- .../basemetals/recipes/starsteel_shield.json | 2 +- .../starsteel_shield_plate_repair.json | 2 +- .../basemetals/recipes/starsteel_shovel.json | 4 +- .../basemetals/recipes/starsteel_slab.json | 4 +- .../recipes/starsteel_smallpowder.json | 4 +- .../basemetals/recipes/starsteel_stairs.json | 4 +- .../basemetals/recipes/starsteel_sword.json | 4 +- .../recipes/starsteel_trapdoor.json | 4 +- .../basemetals/recipes/starsteel_wall.json | 4 +- .../basemetals/recipes/steel_anvil.json | 2 +- .../basemetals/recipes/steel_arrow.json | 4 +- .../assets/basemetals/recipes/steel_axe.json | 4 +- .../basemetals/recipes/steel_bars_1.json | 4 +- .../basemetals/recipes/steel_bars_2.json | 4 +- .../basemetals/recipes/steel_blend_base.json | 4 +- .../recipes/steel_blend_smallblend.json | 4 +- .../basemetals/recipes/steel_block.json | 4 +- .../basemetals/recipes/steel_block_ingot.json | 4 +- .../assets/basemetals/recipes/steel_bolt.json | 4 +- .../basemetals/recipes/steel_boots.json | 4 +- .../recipes/steel_boots_plate_repair.json | 2 +- .../assets/basemetals/recipes/steel_bow.json | 4 +- .../basemetals/recipes/steel_button.json | 4 +- .../basemetals/recipes/steel_chestplate.json | 4 +- .../steel_chestplate_plate_repair.json | 2 +- .../basemetals/recipes/steel_crackhammer.json | 4 +- .../basemetals/recipes/steel_crossbow.json | 4 +- .../assets/basemetals/recipes/steel_door.json | 4 +- .../basemetals/recipes/steel_fishingrod.json | 4 +- .../assets/basemetals/recipes/steel_gear.json | 4 +- .../basemetals/recipes/steel_helmet.json | 4 +- .../recipes/steel_helmet_plate_repair.json | 2 +- .../assets/basemetals/recipes/steel_hoe.json | 4 +- .../basemetals/recipes/steel_horsearmor.json | 4 +- .../basemetals/recipes/steel_ingot.json | 4 +- .../basemetals/recipes/steel_leggings.json | 4 +- .../recipes/steel_leggings_plate_repair.json | 2 +- .../basemetals/recipes/steel_lever.json | 4 +- .../basemetals/recipes/steel_nugget.json | 4 +- .../basemetals/recipes/steel_pickaxe.json | 4 +- .../basemetals/recipes/steel_plate.json | 4 +- .../basemetals/recipes/steel_powder.json | 4 +- .../recipes/steel_pressureplate.json | 4 +- .../assets/basemetals/recipes/steel_rod.json | 3 +- .../basemetals/recipes/steel_scythe.json | 2 +- .../basemetals/recipes/steel_shears.json | 4 +- .../basemetals/recipes/steel_shield.json | 2 +- .../recipes/steel_shield_plate_repair.json | 2 +- .../basemetals/recipes/steel_shovel.json | 4 +- .../assets/basemetals/recipes/steel_slab.json | 4 +- .../recipes/steel_smallblend_blend.json | 4 +- .../basemetals/recipes/steel_smallpowder.json | 4 +- .../basemetals/recipes/steel_stairs.json | 4 +- .../basemetals/recipes/steel_sword.json | 4 +- .../basemetals/recipes/steel_trapdoor.json | 4 +- .../assets/basemetals/recipes/steel_wall.json | 4 +- .../basemetals/recipes/stone_anvil.json | 2 +- .../basemetals/recipes/stone_crackhammer.json | 2 +- .../basemetals/recipes/stone_scythe.json | 2 +- .../assets/basemetals/recipes/tin_arrow.json | 4 +- .../assets/basemetals/recipes/tin_axe.json | 4 +- .../assets/basemetals/recipes/tin_bars_1.json | 4 +- .../assets/basemetals/recipes/tin_bars_2.json | 4 +- .../assets/basemetals/recipes/tin_block.json | 4 +- .../basemetals/recipes/tin_block_ingot.json | 4 +- .../assets/basemetals/recipes/tin_bolt.json | 4 +- .../assets/basemetals/recipes/tin_boots.json | 4 +- .../recipes/tin_boots_plate_repair.json | 2 +- .../assets/basemetals/recipes/tin_bow.json | 4 +- .../assets/basemetals/recipes/tin_button.json | 4 +- .../basemetals/recipes/tin_chestplate.json | 4 +- .../recipes/tin_chestplate_plate_repair.json | 2 +- .../basemetals/recipes/tin_crackhammer.json | 4 +- .../basemetals/recipes/tin_crossbow.json | 4 +- .../assets/basemetals/recipes/tin_door.json | 4 +- .../basemetals/recipes/tin_fishingrod.json | 4 +- .../assets/basemetals/recipes/tin_gear.json | 4 +- .../assets/basemetals/recipes/tin_helmet.json | 4 +- .../recipes/tin_helmet_plate_repair.json | 2 +- .../assets/basemetals/recipes/tin_hoe.json | 4 +- .../basemetals/recipes/tin_horsearmor.json | 4 +- .../assets/basemetals/recipes/tin_ingot.json | 4 +- .../basemetals/recipes/tin_leggings.json | 4 +- .../recipes/tin_leggings_plate_repair.json | 2 +- .../assets/basemetals/recipes/tin_lever.json | 4 +- .../assets/basemetals/recipes/tin_nugget.json | 4 +- .../basemetals/recipes/tin_pickaxe.json | 4 +- .../assets/basemetals/recipes/tin_plate.json | 4 +- .../assets/basemetals/recipes/tin_powder.json | 4 +- .../basemetals/recipes/tin_pressureplate.json | 4 +- .../assets/basemetals/recipes/tin_rod.json | 3 +- .../assets/basemetals/recipes/tin_scythe.json | 2 +- .../assets/basemetals/recipes/tin_shears.json | 4 +- .../assets/basemetals/recipes/tin_shield.json | 2 +- .../recipes/tin_shield_plate_repair.json | 2 +- .../assets/basemetals/recipes/tin_shovel.json | 4 +- .../assets/basemetals/recipes/tin_slab.json | 4 +- .../basemetals/recipes/tin_smallpowder.json | 4 +- .../assets/basemetals/recipes/tin_stairs.json | 4 +- .../assets/basemetals/recipes/tin_sword.json | 4 +- .../basemetals/recipes/tin_trapdoor.json | 4 +- .../assets/basemetals/recipes/tin_wall.json | 4 +- .../basemetals/recipes/tripwire_hook.json | 2 +- .../basemetals/recipes/wood_crackhammer.json | 2 +- .../basemetals/recipes/wood_scythe.json | 2 +- .../assets/basemetals/recipes/zinc_arrow.json | 4 +- .../assets/basemetals/recipes/zinc_axe.json | 4 +- .../basemetals/recipes/zinc_bars_1.json | 4 +- .../basemetals/recipes/zinc_bars_2.json | 4 +- .../assets/basemetals/recipes/zinc_block.json | 4 +- .../basemetals/recipes/zinc_block_ingot.json | 4 +- .../assets/basemetals/recipes/zinc_bolt.json | 4 +- .../assets/basemetals/recipes/zinc_boots.json | 4 +- .../recipes/zinc_boots_plate_repair.json | 2 +- .../assets/basemetals/recipes/zinc_bow.json | 4 +- .../basemetals/recipes/zinc_button.json | 4 +- .../basemetals/recipes/zinc_chestplate.json | 4 +- .../recipes/zinc_chestplate_plate_repair.json | 2 +- .../basemetals/recipes/zinc_crackhammer.json | 4 +- .../basemetals/recipes/zinc_crossbow.json | 4 +- .../assets/basemetals/recipes/zinc_door.json | 4 +- .../basemetals/recipes/zinc_fishingrod.json | 4 +- .../assets/basemetals/recipes/zinc_gear.json | 4 +- .../basemetals/recipes/zinc_helmet.json | 4 +- .../recipes/zinc_helmet_plate_repair.json | 2 +- .../assets/basemetals/recipes/zinc_hoe.json | 4 +- .../basemetals/recipes/zinc_horsearmor.json | 4 +- .../assets/basemetals/recipes/zinc_ingot.json | 4 +- .../basemetals/recipes/zinc_leggings.json | 4 +- .../recipes/zinc_leggings_plate_repair.json | 2 +- .../assets/basemetals/recipes/zinc_lever.json | 4 +- .../basemetals/recipes/zinc_nugget.json | 4 +- .../basemetals/recipes/zinc_pickaxe.json | 4 +- .../assets/basemetals/recipes/zinc_plate.json | 4 +- .../basemetals/recipes/zinc_powder.json | 4 +- .../recipes/zinc_pressureplate.json | 4 +- .../assets/basemetals/recipes/zinc_rod.json | 3 +- .../basemetals/recipes/zinc_scythe.json | 2 +- .../basemetals/recipes/zinc_shears.json | 4 +- .../basemetals/recipes/zinc_shield.json | 2 +- .../recipes/zinc_shield_plate_repair.json | 2 +- .../basemetals/recipes/zinc_shovel.json | 4 +- .../assets/basemetals/recipes/zinc_slab.json | 4 +- .../basemetals/recipes/zinc_smallpowder.json | 4 +- .../basemetals/recipes/zinc_stairs.json | 4 +- .../assets/basemetals/recipes/zinc_sword.json | 4 +- .../basemetals/recipes/zinc_trapdoor.json | 4 +- .../assets/basemetals/recipes/zinc_wall.json | 4 +- .../config/BaseMetalsConfigScreenTest.java | 9 +- ...ientExtensionRegistrationContractTest.java | 7 +- .../ConfigLocalizationContractTest.java | 25 +- .../renderer/BoltRendererContractTest.java | 10 +- .../basemetals/content/ContentPolicyTest.java | 125 +- .../data/DoorRecipeContractTest.java | 17 +- .../data/GameplayAdvancementDataTest.java | 125 + .../data/LootPolicyContractTest.java | 12 + .../data/OreSpawnProviderContractTest.java | 48 +- .../data/RailRecipeAdvancementTest.java | 9 + .../RecipeBookAdvancementCoverageTest.java | 243 ++ .../data/RecipeBookGroupingTest.java | 67 + .../network/ContentModeNetworkTest.java | 12 +- .../BaseMetalsAdvancementRuntimeProbe.java | 339 ++ .../BaseMetalsClientConfigRuntimeProbe.java | 83 +- .../test/BaseMetalsRuntimeProbe.java | 2952 ++++++++++------- .../test/BaseMetalsTinkersRuntimeProbe.java | 678 ++-- .../util/BaseMetalsConfigContractTest.java | 41 +- .../basemetals/util/TestConfigFactory.java | 4 + tools/gen_block_ingot.js | 69 +- tools/gen_recipes.js | 1409 +++++--- tools/os3-format-upgrade/convert-to-2.0.js | 60 +- tools/os3-format-upgrade/os1-to-os3.js | 85 +- 1251 files changed, 8372 insertions(+), 5153 deletions(-) create mode 100644 gradle/data/gameplay-advancements.gradle create mode 100644 gradle/data/recipe-advancements.gradle create mode 100644 gradle/verification/packaged-advancements.gradle create mode 100644 src/main/java/com/mcmoddev/basemetals/advancement/AchievementCondition.java create mode 100644 src/main/java/com/mcmoddev/basemetals/advancement/GameplayAdvancements.java create mode 100644 src/main/java/com/mcmoddev/basemetals/client/config/BaseMetalsGuiFactory.java create mode 100644 src/main/java/com/mcmoddev/basemetals/recipe/PlateRepairFactory.java create mode 100644 src/main/java/com/mcmoddev/basemetals/recipe/PlateRepairRecipe.java create mode 100644 src/main/resources/assets/basemetals/advancements/_factories.json create mode 100644 src/test/java/com/mcmoddev/basemetals/data/GameplayAdvancementDataTest.java create mode 100644 src/test/java/com/mcmoddev/basemetals/data/RecipeBookAdvancementCoverageTest.java create mode 100644 src/test/java/com/mcmoddev/basemetals/data/RecipeBookGroupingTest.java create mode 100644 src/test/java/com/mcmoddev/basemetals/test/BaseMetalsAdvancementRuntimeProbe.java diff --git a/.gitignore b/.gitignore index 3f5193ef..fe874240 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,9 @@ **/registry_audit.md **/registry-audit.md **/bugreport.md +**/validation-*.md +**/*-validation.md +**/test-report*.md # Machine-specific agent context **/AGENTS.md @@ -57,6 +60,12 @@ **/.codex/ **/.claude/ **/.gemini/ +**/.cursor/ +**/.windsurf/ +**/.opencode/ +**/.copilot/ +**/.aider* +**/copilot-instructions.md **/CLAUDE.md **/GEMINI.md **/agent-*.md diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c3d0708e..be509471 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,4 +1,59 @@ -Base Metals 2.5.1.112021 +Base Metals 2.6.0.112021 — Minecraft 1.12.2 + +Before upgrading + +- Back up worlds and configuration. Install MMDLib and OreSpawn + 4.1.0.112021 or newer in the 4.x line on both client and server. +- Old configurations without a content mode stay in High Fantasy. Existing + items and block IDs are retained. +- OreSpawn is now the only Base Metals ore generator. Use OreSpawn overrides + or world settings to disable its rules when another mod generates the ores. + The old MMDLib world-generation switches no longer control Base Metals. + +Gameplay fixes + +- Metal nuggets and powders no longer burn as furnace fuel. Coal and charcoal + forms keep their intended fuel values (#473). +- Doors and trapdoors have distinct recipes. Vanilla-material additions such + as Diamond and Gold doors are registered and available as intended (#474). +- Base Metals Adamantine no longer shares the Adamant alias with TAIGA (#467). +- Fishing rods use their material's durability and retain vanilla fishing wear + rules (#467). +- The Steel rail recipe produces 16 rails, matching the vanilla recipe (#467). +- Crossbows fire bolts on the server, so hits damage their targets. Launcher + and ammunition materials both contribute to ranged damage. Bolts use a valid + projectile texture, and picked-up Base Metals arrows keep their identity (#467). +- Armor effects count equipped pieces correctly and no longer depend on an + undamaged stack. Aquarium's underwater effects and Starsteel's movement + bonuses now apply as intended (#470, #450). +- Tinkers casting and alloy registration skip disabled or missing materials + and fluids instead of crashing, including disabled Prismarine additions (#455). +- Hoes report the tool-material name expected by Ancient Warfare 2 (#449). +- The native OreSpawn provider replaces the old plugin and fallback generator. + Its eleven rules retain their defaults and customized migration values, and + can be disabled without duplicate fallback generation (#448, #428). +- Recipe-book unlocks recognize matching Ore Dictionary ingredients. Recipes + are grouped by their result instead of merging whole weapon and tool families. +- Plate repair requires exactly one damaged armor piece or shield and one + matching plate. It preserves NBT, rejects extra ingredients, and no longer + appears as a misleading plate-only recipe in the recipe book. +- Restored the 18 historical gameplay achievements, including Juggernaut, + SCUBA Diver, and Moon Walker, with saved advancement progress. + +Configuration + +- Added High Fantasy and Low Fantasy content modes. High Fantasy keeps the + historical content; Low Fantasy limits acquisition to suitable material forms. + Items remain registered and available in creative mode in both modes. +- Crafting, processing, trades, chest loot, and supported integrations respect + the selected mode. Clients and servers must use the same effective mode. +- Added the configuration screen to Forge's Mods list and OreSpawn's cog. + It has localized labels and help in all 18 language files, cancellation, + reset controls, restart guidance, and warnings before disabling generated ores. +- Content modes are installation-wide settings. They do not change OreSpawn + distributions or overwrite existing world profiles. + +Build and delivery - Modernized the Minecraft 1.12.2 build on ForgeGradle 7, Gradle 9.6.1 and checksum-pinned Java and mod dependencies. @@ -8,10 +63,11 @@ Base Metals 2.5.1.112021 - Isolated ordinary Eclipse launches from compile-only integration APIs, so optional mods such as CoFH Core are not accidentally loaded without their dependencies, while preserving Forge's order-sensitive runtime classpath. -- Updated the development target to Forge 14.23.5.2859 while preserving Java 8 - game compatibility, registry IDs, OreSpawn 3 behavior and integrations. -- This modernization contains no gameplay or recipe-loop fixes; those changes - will follow separately. +- Updated the development target to Forge 14.23.5.2859 and OreSpawn + 4.1.0.112021 while retaining Java 8 game compatibility. +- Replaced the retired build services with pinned GitHub Actions checks and + a guarded Maven, CurseForge, and GitHub release workflow (#468). +- Split the build scripts by purpose and cleaned up source layout and comments. Base Metals 2.5.0-rc2.332 diff --git a/README.md b/README.md index 773e1716..d40eaced 100644 --- a/README.md +++ b/README.md @@ -1,120 +1,135 @@ -[![](https://img.shields.io/badge/Discord-MMD-green.svg?style=flat&logo=Discord)](https://discord.mcmoddev.com) -[![CurseForge](http://cf.way2muchnoise.eu/base-metals.svg)](https://www.curseforge.com/minecraft/mc-mods/base-metals) -[![Versions](http://cf.way2muchnoise.eu/versions/base-metals.svg)](https://www.curseforge.com/minecraft/mc-mods/base-metals) -[![Build Status](https://ci.mcmoddev.com/job/Base%20Metals/job/Base%20Metals%201.12/badge/icon)](https://ci.mcmoddev.com/job/Base%20Metals/job/Base%20Metals%201.12/) +[![Discord](https://img.shields.io/badge/Discord-MMD-green.svg?style=flat&logo=Discord)](https://discord.moddev.zone) +[![CurseForge downloads](https://cf.way2muchnoise.eu/full_base-metals_downloads.svg)](https://www.curseforge.com/minecraft/mc-mods/base-metals) +[![Minecraft versions](https://cf.way2muchnoise.eu/versions/Minecraft_base-metals_all.svg)](https://www.curseforge.com/minecraft/mc-mods/base-metals) +[![Build, test, and audit](https://github.com/MinecraftModDevelopmentMods/BaseMetals/actions/workflows/ci.yml/badge.svg?branch=master-1.12)](https://github.com/MinecraftModDevelopmentMods/BaseMetals/actions/workflows/ci.yml?query=branch%3Amaster-1.12) +[![CodeQL](https://github.com/MinecraftModDevelopmentMods/BaseMetals/actions/workflows/codeql-analysis.yml/badge.svg?branch=master-1.12)](https://github.com/MinecraftModDevelopmentMods/BaseMetals/actions/workflows/codeql-analysis.yml?query=branch%3Amaster-1.12) + +# Base Metals for Minecraft 1.12.2 + +Base Metals adds metals, alloys, equipment, building blocks, and the crackhammer. +Crush ores into powder, smelt the powder into ingots, or combine it into alloy +blends. The metals also work with supported processing and tool-building mods. + +This branch builds **2.6.0.112021** for Minecraft 1.12.2 and Forge. It keeps the +existing block and item names for saved worlds, fixes long-standing gameplay +issues, and adds an optional Low Fantasy content mode. See the +[changelog](CHANGELOG.txt) for the release changes. -## Base Metals Mod +## Installation -This mod adds historically commonly used metals to Minecraft, specifically Silver, Copper, Tin, Lead, Zinc, Mercury, and Nickel. You will also find a number of metal alloys in this mod and a new tool: the Crack Hammer. +Install these mods on both the client and server: -Fantasy metals have been added to the Nether and the End: Cold Iron, Mithril, Adamantine, and Star Steel +- [Minecraft Forge](https://files.minecraftforge.net/net/minecraftforge/forge/index_1.12.2.html) + 14.23.5.2859 or newer for Minecraft 1.12.2. +- [MMDLib](https://www.curseforge.com/minecraft/mc-mods/mmdlib), tested with + `1.0.0-rc2.36`. +- [MMD OreSpawn](https://www.curseforge.com/minecraft/mc-mods/mmd-orespawn) + `4.1.0.112021` or newer in the 4.x line. +- [Base Metals](https://www.curseforge.com/minecraft/mc-mods/base-metals). +Put the jars in the instance's `mods` folder. Minecraft 1.12.2 runs on Java 8. +Back up your worlds and configuration before upgrading. MMD OreSpawn is the +world-generation library, not the unrelated creature mod with a similar name. +## Metals and alloys -## Metals and Alloys +The natural materials are Antimony, Bismuth, Copper, Lead, Mercury, Nickel, +Platinum, Silver, Tin, and Zinc. The alloys are Brass, Bronze, Cupronickel, +Electrum, Invar, Pewter, and Steel. Adamantine, Aquarium, Cold Iron, Mithril, +and Starsteel provide the fantasy materials. -###Natural Metals +OreSpawn places Cold Iron and Adamantine in the Nether and Starsteel in the +End. Copper, Silver, Tin, Lead, Zinc, Mercury, Nickel, and Platinum generate +in ordinary dimensions. Antimony and Bismuth ore blocks are available, but +they do not generate by default. Aquarium and Mithril are alloys, not ores. -**Antimony**: +Make alloys by combining powders in a crafting grid and smelting the resulting +blend. For example, Bronze uses Copper and Tin; Steel uses Iron and carbon. +Vanilla Bits adds useful forms for vanilla materials, such as Iron powder, +Stone crackhammers, and Obsidian tools. -**Bismuth**: +## Crackhammers and equipment -**Copper**: Copper is soft, easy to work, and fairly abundant. It is needed to make bronze and brass metal alloys. +Mine a crushable block with a crackhammer to get its powdered ingredients. +Many metal ores yield two powders, which can be smelted into ingots. You can +also drop items on the ground and use the hammer on the block beneath them. +The exact output depends on the crusher recipe. -**Lead**: Lead is a very soft metal that is best known for being very heavy and somewhat toxic. Lead tools are fragile, but can dish out a lot of damage when used as weapons. +Material choice affects the damage of Base Metals bows, arrows, crossbows, +and bolts. Crossbows use the mod's original draw-and-release behaviour; they +do not store a charged shot. Ordinary vanilla bow-and-arrow damage is unchanged. -**Mercury**: This toxic liquid metal has many alchemical uses. The Mithril metal alloys requires mercury. +Some materials have additional effects: -**Nickel**: This metal is as soft as copper, but it has alchemical properties and forms the invar metal alloy when mixed with iron. +- Adamantine armor grants Resistance, and its melee tools are stronger against + creatures with more than 20 maximum health. +- A complete Aquarium suit grants Water Breathing and Resistance while in + water and removes Mining Fatigue. +- A complete Cold Iron suit grants Fire Resistance. +- A complete Mithril suit removes harmful effects. +- Lead armor slows its wearer. +- Starsteel armor grants Jump Boost and, from two pieces onward, Speed. + Held Starsteel equipment slowly repairs itself. -**Platinum**: +One matching plate fully repairs a damaged armor piece or shield in a crafting +grid, preserving its enchantments and name. This uses MMDLib's +`repair_using_plates` setting. -**Silver**: Silver is a soft, shiny metal that is valued for both is beauty and its alchemical uses. +## Configuration -**Tin**: Tin is an extremely soft metal that is not useful by itself, but can be combined with copper to make bronze, a metal alloy nearly as strong as iron. +Open **Mods → Base Metals → Config** from the main menu, or use the Base Metals +cog under **Create World → OreSpawn → Mods**. Both open the same configuration +screen. Changes require a Minecraft restart. -**Zinc**: Like tin, zinc is worthless on its own, but can be used to make the metal alloy brass. +- **High Fantasy** is the default and keeps the historical content available. +- **Low Fantasy** limits equipment and building recipes to suitable materials. + It does not remove existing items or change ore generation. +An old configuration without `contentMode` still uses High Fantasy. The mode +applies to the whole Minecraft instance or server, not to one world. Clients +and servers must use the same mode. +OreSpawn is the only Base Metals ore generator. Edit ore rules in OreSpawn, +not through MMDLib's old `using_orespawn` or `fallback_orespawn` switches. +Existing OreSpawn world settings and explicit overrides are preserved. -###Metal Alloys -*Metal alloys are made by crafting together the powdered forms of the required metals, and then smelting the resulting alloy blend in a furnace.* +See the [configuration guide](docs/configuration.md) and +[world-generation guide](docs/world-generation.md), including the example +for letting CoFH World place the ores instead. -**Brass**: This alloy of copper and zinc (2:1 ratio) is soft, but has a beautiful golden color. +## Mod compatibility -**Bronze**: This alloy of copper and tin (3:1 ratio) is as hard as iron, but not quite as durable. +Base Metals includes optional integrations for Tinkers' Construct, Construct's +Armory, Thermal Expansion, Mekanism, Ender IO, IC2, Thaumcraft, Dense Ores, +VeinMiner, and Additional Loot Tables. Ore Dictionary entries let other mods +use the materials without a dedicated integration. These mods are not required +for an ordinary Base Metals installation. -**Electrum**: This alloy of silver and gold (1:1 ratio) can be enchanted like gold, but is slightly more durable. +The Tinkers integration keeps Base Metals Adamantine separate from TAIGA's +Adamant. Low Fantasy also restricts the equipment routes exposed by supported +integrations. -**Invar**: This alloy of iron and nickel (2:1 ratio) is harder than steel, but less durable. +The [Brittle modifier crash at one durability](https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues/485) +belongs to MMDLib and is not fixed by this Base Metals release. -**Pewter**: +## Building and contributing -**Steel**: This alloy of iron and carbon (8:1 ratio) is as hard as iron and much more durable. +Use the Gradle wrapper. Gradle runs on Java 17; the build uses Java 25 for +ForgeGradle's Mavenizer and Java 8 to compile and run Minecraft. The exact +toolchain and dependency versions are recorded in `gradle.properties`. + +```text +./gradlew check build javadoc verifyReleaseArtifacts +./gradlew prepareEclipse +``` +`prepareEclipse` creates client and server launches with processed resources +and keeps optional compile-only mods and test code out of normal launches. +The [build-script guide](gradle/README.md) explains the supporting scripts. -###Fantasy Metals - -**Adamantine**: (found in the Nether): Adamantine is a rare magical metal that is as strong as diamond, maybe even stronger. Armor made from Adamantine grants resistance to damage and tools made from adamantine are extra effective against monsters that have more than 10 hearts of health. - -**Aquarium**: - -**Cold-Iron**: (found in the Nether): Cold-Iron is a magical metal that is as strong as iron. Tools made from Cold Iron are extra effective against denizens of the Nether and any creature that is immune to fire. - -**Mithril**: Mithril is an alloy of alloy of silver, mercury, and cold-iron (2:1:1 ratio). It is as strong as steel and Mithril weapons are extra effective against undead. - -**Star-Steel**: (found in the End): Armor made from Star Steel reduces the weight of the wearer, allowing the wearer to jump higher and fall slower. Star-Steel tools slowly repair themselves while held. - - - -## Crack Hammer - -Also known as a sledgehammer, this tool is designed for pulverizing rocks. Using this tool on ores will cause them to drop powdered metal instead of the standard ore block. Use can then use the powdered metals to make metal alloy mixes or just smelt the powder into ingots. You can crush items by dropping them on the ground and then right-clicking on the ground beneath the items. - - - -## Requirements - -Base Metals 2.6.0 requires Minecraft 1.12.2, Forge 14.23.5.2859, MMDLib, -and OreSpawn 4.1.0.112021 or newer in the 4.x line. - -OreSpawn 4.1's Mods directory includes a Base Metals cog for editing the -existing `BaseMetals.cfg`. See [configuration](docs/configuration.md) for the -restart and ore-rule safety behavior, including the upgrade-safe High Fantasy, -Low Fantasy, and Realism content modes. Existing configurations without a mode -remain in High Fantasy and keep the historical recipes and acquisition paths. - -OreSpawn is the sole Base Metals ore generator. To disable Base Metals' rules -for a CoFH World or other custom-worldgen setup, follow the -[world-generation guide](docs/world-generation.md). The old MMDLib -`using_orespawn` and `fallback_orespawn` options do not control these rules. - - - -## Installing - -After you have successfully installed Forge, simply place the file *basemetals-#.#.#.jar* in your *mods* folder. You can get the basemetals-#.#.jar file from the Releases tab of this repository page. - -##NEI - -The Crack Hammer recipes from this mod will appear in NEI if you have NEI installed. Hooray! - - -## Mod API - -Check the developer releases to download the files *basemetals-#.#.#-deobf.jar*, *basemetals-#.#.#-sources.jar*, *basemetals-#.#.#-javadoc.jar*. In your Eclipse project (and *build.gradle* file), add *basemetals-#.#.#-deobf.jar* as a library dependency. All items and blocks can be conveniently accessed via classes in the *com.mcmoddev.basemetals.init* package. New recipes for the Crack Hammer can be added via the *com.mcmoddev.lib.registry.CrusherRecipeRegistry* class. - - -## Q&A - -Q: Why make this mod? - -A: Minecraft appears to have a pre-industrial fantasy setting, but the fantasy literature (and pre-industrial history) is full of references to silver and copper as well as gold. - - - -Q: What does the Crack Hammer do? - -A: When you break ores with the Crack Hammer, you get two piles of metal powders instead of a single block of ore. This is necessary to make metal alloys, which is done by combining the powders of the various components and then smelting the alloy mix. - +Release artifacts use the Maven coordinates +`zone.moddev.mc.basemetals:BaseMetals:2.6.0.112021`. Java packages remain under +`com.mcmoddev.basemetals`; this release does not move saved registry names. +Report bugs through the [issue tracker](https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues). +Include your mod versions, relevant configuration, and a log or crash report. diff --git a/build.gradle b/build.gradle index 5d92b0c6..a8a52149 100644 --- a/build.gradle +++ b/build.gradle @@ -198,10 +198,11 @@ repositories { } apply from: 'gradle/dependencies.gradle' +apply from: 'gradle/data/recipe-advancements.gradle' +apply from: 'gradle/data/gameplay-advancements.gradle' -// Renamer Gradle replaces ForgeGradle's retired deobfProvided configuration. -// Dependencies are mapped from their production SRG names to stable_39 for the -// development compile/runtime classpaths; the public jar is mapped back below. +// Use readable stable_39 names in development. Reobfuscate the release jar +// back to SRG names so it works in a normal Forge installation. renamer.mappings.from minecraft.dependency.toSrgFile tasks.named('processResources', ProcessResources) { @@ -289,8 +290,7 @@ ext.baseMetalsBuild = [ releaseJar : releaseJar ].asImmutable() -// Keep the root build focused on compiling the mod. The applied scripts group -// release qualification, packaged runtime checks, publishing, and IDE support. +// Build details are split by purpose: data, release checks, runtime tests, and Eclipse. apply from: 'gradle/verification/support.gradle' apply from: 'gradle/release/artifacts.gradle' apply from: 'gradle/verification/packaged-forge.gradle' diff --git a/docs/configuration.md b/docs/configuration.md index 274f79be..fc0932e8 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -4,6 +4,9 @@ With OreSpawn 4.1 or newer installed, Base Metals contributes one configuration screen to OreSpawn's world-creation interface. Open **Create World → OreSpawn → Mods**, then use the cog beside Base Metals. +You can also open the same screen from the main menu through **Mods → Base +Metals → Config**. + The screen edits the existing `config/BaseMetals.cfg` file. It does not create a second configuration file. It exposes the existing 92 boolean settings plus the restart-required `General/contentMode` selector under the five historical @@ -28,6 +31,13 @@ Done saves through Forge's normal Base Metals configuration event. Escape discards edits on both category and root pages. Forge supplies the standard Undo, Defaults, and restart-confirmation behavior. +The **Achievements** setting controls the 18 historical gameplay achievements, +including Juggernaut for a complete equipped Adamantine suit, SCUBA Diver for +a submerged Aquarium suit, and Moon Walker for equipped Starsteel boots. +They appear as advancements with the usual notification. Disabling a material +also omits achievements that require its items; it is safe to leave achievements +enabled. Recipe-book unlocks operate independently of this setting. + ## Content modes - **High Fantasy** (`high_fantasy`) is the default and preserves the complete @@ -35,23 +45,21 @@ Undo, Defaults, and restart-confirmation behavior. - **Low Fantasy** (`low_fantasy`) keeps fantasy materials but removes equipment and construction forms that do not fit the reviewed material policy. Base Metals bows, crossbows, and fishing rods are unavailable in this mode. -- **Realism** (`realism`) applies the Low Fantasy restrictions and also removes - normal acquisition of Adamantine, Aquarium, Cold Iron, Mithril, and - Star-Steel. Their registered items and blocks remain available to load old - saves and can still be obtained deliberately through commands, creative mode, - or third-party data supplied by a pack. An older `BaseMetals.cfg` without `contentMode` is treated exactly like an -explicit `high_fantasy` configuration. Invalid values are corrected to High -Fantasy. The effective value is latched during startup, and a client whose -effective mode differs from the server is disconnected with an explanatory +explicit `high_fantasy` configuration. Unrecognized values are corrected to High +Fantasy. The mode is chosen when Minecraft starts. A client using a different +mode from the server is disconnected with an explanatory Base Metals message before gameplay. -Changing mode never rewrites an existing OreSpawn global override or saved -world profile. In particular, switching to Realism does not silently disable -fantasy rules in an existing world; review those rules in OreSpawn and disable -them manually when desired. Fresh Realism profiles default Adamantine, Cold -Iron, and Star-Steel generation off. +The mode belongs to the Minecraft instance or dedicated server, not to an +individual save. After a restart, the selected mode applies to every world +opened with that installation, including existing worlds. Base Metals does +not prompt or block a world whose previous session used a different mode. + +Content modes do not change OreSpawn's eleven ore rules. To disable ore +generation, edit the rules in OreSpawn separately. Existing global overrides +and saved-world profiles are not rewritten when the mode changes. ## OreSpawn dependency diff --git a/docs/world-generation.md b/docs/world-generation.md index 47781f14..e9a56e34 100644 --- a/docs/world-generation.md +++ b/docs/world-generation.md @@ -4,16 +4,15 @@ Base Metals 2.6.0 requires OreSpawn 4.1.0.112021 or newer in the 4.x line. OreSpawn is the only Base Metals ore generator. Base Metals does not register a fallback generator. -Base Metals submits a schema-5 API provider at revision 2 containing eleven -stable rules. Cold iron and Adamantine generate -in the Nether, Star-Steel generates in the End, and copper, silver, tin, lead, +Base Metals supplies eleven ore rules through OreSpawn's API (schema 5, +provider revision 2). Cold Iron and Adamantine generate +in the Nether, Starsteel generates in the End, and copper, silver, tin, lead, zinc, mercury, nickel and platinum generate in ordinary dimensions. Existing registry names and the historical distribution values are preserved. -High Fantasy and Low Fantasy enable all eleven rules by default. A fresh -Realism profile defaults Adamantine, Cold Iron, and Star-Steel off. Existing -global overrides and saved-world profiles remain authoritative when the mode -changes and are never rewritten silently. +High Fantasy and Low Fantasy both enable all eleven rules by default. Content +mode does not change OreSpawn world generation. Existing global overrides and +saved-world profiles remain authoritative and are never rewritten silently. ## Letting another mod generate the ores diff --git a/gradle/README.md b/gradle/README.md index c06a1502..144935ed 100644 --- a/gradle/README.md +++ b/gradle/README.md @@ -9,6 +9,9 @@ of that main path: - `dependencies.gradle` owns exact third-party coordinates and the matching development, fixture, and verification configurations. +- `data/recipe-advancements.gradle` derives recipe-book discovery advancements + from the shipped recipe catalogue and preserves each recipe's conditions. +- `data/gameplay-advancements.gradle` restores the historical achievement tree. - `verification/support.gradle` defines shared toolchain, dependency, JSON, and OreSpawn provider checks. - `verification/packaged-forge.gradle` prepares the common clean Forge runtime @@ -20,14 +23,15 @@ of that main path: coexistence profile. - `verification/packaged-forge-tinkers.gradle` covers Tinkers, TAIGA, Construct's Armory, and content-mode combinations. +- `verification/packaged-advancements.gradle` checks gameplay achievements, + saved progress, disabled settings, and Low Fantasy in disposable worlds. - `release/artifacts.gradle` audits release jars and writes checksums. - `release/publishing.gradle` defines guarded Maven publication. - `ide/eclipse.gradle` generates and verifies isolated Eclipse launches. - `verification/workflows.gradle` checks the pinned GitHub Actions contracts. -Shared values are exposed through small immutable maps. This lets an applied -script state which part of the build contract it uses instead of depending on -variables that happen to exist in another script's scope. +Scripts share settings through small immutable maps rather than relying on +variables from another script's scope. When adding a task, put it beside the workflow it supports. Keep task names stable because CI and the release dispatcher call them directly. diff --git a/gradle/data/gameplay-advancements.gradle b/gradle/data/gameplay-advancements.gradle new file mode 100644 index 00000000..f5913d7e --- /dev/null +++ b/gradle/data/gameplay-advancements.gradle @@ -0,0 +1,73 @@ +import groovy.json.JsonOutput + +// Keep the historical names and IDs so these achievements carry forward to newer ports. +def definitions = [ + this_is_new : ['minecraft:story/smelt_iron', 'minecraft:iron_ingot', 'task'], + blocktastic : ['basemetals:this_is_new', 'minecraft:iron_block', 'task'], + geologist : ['basemetals:this_is_new', 'minecraft:iron_pickaxe', 'task'], + metallurgy : ['basemetals:geologist', 'minecraft:cauldron', 'task'], + aquarium_maker : ['basemetals:metallurgy', 'basemetals:aquarium_ingot', 'goal'], + brass_maker : ['basemetals:metallurgy', 'basemetals:brass_ingot', 'goal'], + bronze_maker : ['basemetals:metallurgy', 'basemetals:bronze_ingot', 'goal'], + cupronickel_maker: ['basemetals:metallurgy', 'basemetals:cupronickel_ingot', 'goal'], + electrum_maker : ['basemetals:metallurgy', 'basemetals:electrum_ingot', 'goal'], + invar_maker : ['basemetals:metallurgy', 'basemetals:invar_ingot', 'goal'], + mithril_maker : ['basemetals:metallurgy', 'basemetals:mithril_ingot', 'goal'], + pewter_maker : ['basemetals:metallurgy', 'basemetals:pewter_ingot', 'goal'], + steel_maker : ['basemetals:metallurgy', 'basemetals:steel_ingot', 'goal'], + angel_of_death : ['basemetals:mithril_maker', 'basemetals:mithril_sword', 'challenge'], + scuba_diver : ['basemetals:aquarium_maker', 'basemetals:aquarium_helmet', 'challenge'], + demon_slayer : ['minecraft:story/enter_the_nether', 'basemetals:coldiron_sword', 'challenge'], + juggernaut : ['minecraft:story/enter_the_nether', 'basemetals:adamantine_chestplate', 'challenge'], + moon_boots : ['minecraft:end/root', 'basemetals:starsteel_boots', 'challenge'] +].asImmutable() + +def equipmentMaterials = [ + angel_of_death: 'mithril', scuba_diver: 'aquarium', + demon_slayer: 'coldiron', juggernaut: 'adamantine' +] +def outputDirectory = layout.buildDirectory.dir('generated-resources/gameplay-advancements') + +def generate = tasks.register('generateGameplayAdvancements') { + group = 'build' + description = 'Restores the 18 historical achievements as configuration-aware advancements.' + inputs.property('definitions', definitions) + inputs.property('equipmentMaterials', equipmentMaterials) + outputs.dir(outputDirectory) + doLast { + File root = outputDirectory.get().asFile + project.delete(root) + definitions.each { id, definition -> + String parent = definition[0] + String icon = definition[1] + List requiredItems = [icon] + if (equipmentMaterials.containsKey(id)) { + String material = equipmentMaterials[id] + requiredItems.addAll(['helmet', 'chestplate', 'leggings', 'boots'].collect { + "basemetals:${material}_${it}".toString() + }) + } + if (parent.startsWith('basemetals:')) { + requiredItems.add(definitions[parent.substring('basemetals:'.length())][1]) + } + Map advancement = [ + parent: parent, + display: [ + icon: [item: icon], + title: [translate: "achievement.${id}"], + description: [translate: "achievement.${id}.desc"], + frame: definition[2], show_toast: true, announce_to_chat: true + ], + criteria: [event: [trigger: 'minecraft:impossible']], + conditions: [[type: 'basemetals:achievement', items: requiredItems.unique()]] + ] + File output = new File(root, "assets/basemetals/advancements/${id}.json") + output.parentFile.mkdirs() + output.setText(JsonOutput.prettyPrint(JsonOutput.toJson(advancement)) + '\n', 'UTF-8') + } + } +} + +sourceSets.main.resources.srcDir(outputDirectory) +tasks.named('processResources') { dependsOn generate } +tasks.named('sourcesJar') { dependsOn generate } diff --git a/gradle/data/recipe-advancements.gradle b/gradle/data/recipe-advancements.gradle new file mode 100644 index 00000000..57c375d5 --- /dev/null +++ b/gradle/data/recipe-advancements.gradle @@ -0,0 +1,160 @@ +import groovy.json.JsonOutput +import groovy.json.JsonSlurper + +def recipeDirectory = file('src/main/resources/assets/basemetals/recipes') +def generatedResourceDirectory = layout.buildDirectory.dir( + 'generated-resources/recipe-advancements') + +// Ingots from other mods should unlock the same recipes. Match ore-dictionary +// names rather than a particular mod's items. +def materialOres = [ + adamantine : 'ingotAdamantine', + antimony : 'ingotAntimony', + aquarium : 'ingotAquarium', + bismuth : 'ingotBismuth', + brass : 'ingotBrass', + bronze : 'ingotBronze', + charcoal : 'charcoal', + coal : 'coal', + coldiron : 'ingotColdiron', + copper : 'ingotCopper', + cupronickel: 'ingotCupronickel', + diamond : 'gemDiamond', + electrum : 'ingotElectrum', + emerald : 'gemEmerald', + gold : 'ingotGold', + invar : 'ingotInvar', + iron : 'ingotIron', + lead : 'ingotLead', + mithril : 'ingotMithril', + nickel : 'ingotNickel', + obsidian : 'ingotObsidian', + pewter : 'ingotPewter', + platinum : 'ingotPlatinum', + quartz : 'gemQuartz', + redstone : 'dustRedstone', + silver : 'ingotSilver', + starsteel : 'ingotStarsteel', + steel : 'ingotSteel', + stone : 'stone', + tin : 'ingotTin', + wood : 'logWood', + zinc : 'ingotZinc' +].asImmutable() + +def genericSteelRecipes = [ + 'activator_rail', 'detector_rail', 'flint_and_steel', 'human_detector', + 'minecart', 'piston', 'rail', 'tripwire_hook' +] as Set + +def materialForRecipe = { String recipeName -> + if (genericSteelRecipes.contains(recipeName)) { + return 'steel' + } + materialOres.keySet().find { String material -> + recipeName == material || recipeName.startsWith("${material}_") + } +} + +Closure advancementConditions +advancementConditions = { Object value -> + if (value instanceof Map) { + return value.collectEntries { Object key, Object child -> + Object translated = child + if (key == 'type' && child instanceof String + && child.startsWith('mmdlib:')) { + translated = "basemetals:${child.substring('mmdlib:'.length())}" + } else { + translated = advancementConditions(child) + } + [(key): translated] + } + } + if (value instanceof List) { + return value.collect { Object child -> advancementConditions(child) } + } + value +} + +def generateRecipeBookAdvancements = tasks.register('generateRecipeBookAdvancements') { + group = 'build' + description = 'Generates condition-aware recipe-book advancements for every Base Metals recipe.' + inputs.files(fileTree(recipeDirectory) { + include '*.json' + exclude '_factories.json' + }) + inputs.property('materialOres', materialOres) + inputs.property('genericSteelRecipes', genericSteelRecipes.toList().sort()) + outputs.dir(generatedResourceDirectory) + + doLast { + File outputRoot = generatedResourceDirectory.get().asFile + project.delete(outputRoot) + File advancementRoot = new File(outputRoot, + 'assets/basemetals/advancements/recipes/materials') + JsonSlurper parser = new JsonSlurper() + + fileTree(recipeDirectory) { + include '*.json' + exclude '_factories.json' + }.files.sort { left, right -> left.name <=> right.name }.each { File recipeFile -> + String recipeName = recipeFile.name.substring(0, + recipeFile.name.length() - '.json'.length()) + // The recipe book cannot show the damaged item needed for a repair. + if (recipeName.endsWith('_plate_repair')) { + return + } + String material = materialForRecipe(recipeName) + if (material == null) { + throw new GradleException( + "No recipe-book discovery material is defined for ${recipeName}") + } + + Map recipe = parser.parse(recipeFile) as Map + Map advancement = [ + parent : 'minecraft:recipes/root', + rewards : [recipes: ["basemetals:${recipeName}"]], + criteria : [ + has_material : [ + trigger : 'minecraft:inventory_changed', + conditions: [items: [[ + type: 'forge:ore_dict', + ore : materialOres[material] + ]]] + ], + has_the_recipe: [ + trigger : 'minecraft:recipe_unlocked', + conditions: [recipe: "basemetals:${recipeName}"] + ] + ], + requirements: [['has_material', 'has_the_recipe']] + ] + if (recipe.containsKey('conditions')) { + // Omit unlocks for disabled recipes too. Forge uses separate factory + // registries for recipes and advancements, so these aliases are needed. + advancement.conditions = advancementConditions(recipe.conditions) + } + + File output = new File(advancementRoot, + "${material}/${recipeName}.json") + output.parentFile.mkdirs() + output.setText(JsonOutput.prettyPrint(JsonOutput.toJson(advancement)) + + '\n', 'UTF-8') + } + } +} + +sourceSets.main.resources.srcDir(generatedResourceDirectory) + +tasks.named('processResources') { + dependsOn generateRecipeBookAdvancements +} + +tasks.named('sourcesJar') { + dependsOn generateRecipeBookAdvancements +} + +ext.baseMetalsRecipeAdvancements = [ + outputDirectory: generatedResourceDirectory, + generateTask : generateRecipeBookAdvancements +].asImmutable() diff --git a/gradle/release/artifacts.gradle b/gradle/release/artifacts.gradle index d20941bd..f77a05fb 100644 --- a/gradle/release/artifacts.gradle +++ b/gradle/release/artifacts.gradle @@ -125,26 +125,31 @@ tasks.register('verifyReleaseArtifacts') { // Base Metals' steel rail alternative previously had no // recipe-book discovery advancement. 'assets/basemetals/advancements/recipes/transportation/rail.json', + // Forge loads this factory before evaluating the copied recipe + // conditions on generated recipe-book advancements. + 'assets/basemetals/advancements/_factories.json', + // Restores the historical gameplay achievements on Forge 1.12. + 'com/mcmoddev/basemetals/advancement/AchievementCondition.class', + 'com/mcmoddev/basemetals/advancement/GameplayAdvancements.class', // Replaces MMDLib's client-only 1.12 crossbow firing path. 'com/mcmoddev/basemetals/items/ItemBaseMetalsCrossbow.class', - // Applies the established material attack statistic to both - // components of Base Metals ranged attacks. + // Includes both launcher and ammunition materials in shot damage. 'com/mcmoddev/basemetals/items/ItemBaseMetalsArrow.class', 'com/mcmoddev/basemetals/items/ItemBaseMetalsBolt.class', 'com/mcmoddev/basemetals/items/ItemBaseMetalsBow.class', - // Restores ItemHoe's vanilla material-name contract for - // compatibility consumers such as Ancient Warfare 2. + // Returns the tool-material name expected by Ancient Warfare 2. 'com/mcmoddev/basemetals/items/ItemBaseMetalsHoe.class', 'com/mcmoddev/basemetals/items/MaterialRangedDamage.class', // Replaces MMDLib's reference to a nonexistent bolt texture. 'com/mcmoddev/basemetals/client/renderer/RenderBaseMetalsBolt.class', - // Exposes the existing BaseMetals.cfg through OreSpawn 4.1's - // client-only world-settings extension point. + // Adds Base Metals config screens to OreSpawn's cog button. 'com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen.class', 'com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen$CategoryElement.class', 'com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen$CategoryEntry.class', 'com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen$CategoryScreen.class', - // Upgrade-safe content policy, filtering, loot and handshake. + // Connects the same screen to Forge's Mods-list Config button. + 'com/mcmoddev/basemetals/client/config/BaseMetalsGuiFactory.class', + // Content modes, recipe and loot filtering, and the connection check. 'com/mcmoddev/basemetals/content/ContentMode.class', 'com/mcmoddev/basemetals/content/ContentPolicy.class', 'com/mcmoddev/basemetals/content/MaterialForm.class', @@ -155,6 +160,8 @@ tasks.register('verifyReleaseArtifacts') { 'com/mcmoddev/basemetals/network/ContentModeNetwork.class', 'com/mcmoddev/basemetals/network/ContentModeNetwork$ServerHandler.class', 'com/mcmoddev/basemetals/recipe/ContentAcquisitionFilters.class', + 'com/mcmoddev/basemetals/recipe/PlateRepairFactory.class', + 'com/mcmoddev/basemetals/recipe/PlateRepairRecipe.class', 'com/mcmoddev/basemetals/recipe/PolicyCrusherRecipe.class', 'com/mcmoddev/basemetals/recipe/PolicyRecipe.class', 'com/mcmoddev/basemetals/worldgen/BaseMetalsWorldgenProvider.class', @@ -171,12 +178,21 @@ tasks.register('verifyReleaseArtifacts') { 'com/mcmoddev/orespawn/BaseMetalsOreSpawn.class', 'com/mcmoddev/orespawn/package-info.class', 'assets/basemetals/orespawn/basemetals.json', - // These source files were deliberately removed on master-1.12 - // after 2.5.0-rc2.332; the modernization does not resurrect them. + // These classes were removed after 2.5.0-rc2.332. 'com/mcmoddev/basemetals/items/MMDToolEffects.class', 'com/mcmoddev/basemetals/items/package-info.class' ] - List unexpectedAdded = (currentInventory - legacyInventory) - allowedAddedEntries + List generatedRecipeAdvancements = currentInventory.findAll { String entry -> + entry ==~ /assets\/basemetals\/advancements\/recipes\/materials\/[^\/]+\/[^\/]+\.json/ + } + allowedAddedEntries.addAll([ + 'this_is_new', 'blocktastic', 'geologist', 'metallurgy', + 'aquarium_maker', 'brass_maker', 'bronze_maker', 'cupronickel_maker', + 'electrum_maker', 'invar_maker', 'mithril_maker', 'pewter_maker', 'steel_maker', + 'angel_of_death', 'scuba_diver', 'demon_slayer', 'juggernaut', 'moon_boots' + ].collect { "assets/basemetals/advancements/${it}.json".toString() }) + List unexpectedAdded = (currentInventory - legacyInventory) \ + - allowedAddedEntries - generatedRecipeAdvancements List unexpectedRemoved = (legacyInventory - currentInventory) - allowedRemovedEntries if (!unexpectedAdded.isEmpty() || !unexpectedRemoved.isEmpty() || !allowedAddedEntries.every { currentInventory.contains(it) } diff --git a/gradle/release/publishing.gradle b/gradle/release/publishing.gradle index bd36bca4..16d8dd89 100644 --- a/gradle/release/publishing.gradle +++ b/gradle/release/publishing.gradle @@ -2,7 +2,7 @@ def releaseJar = project.ext.baseMetalsBuild.releaseJar def expectedReleaseFiles = project.ext.baseMetalsVerification.expectedReleaseFiles def preparedReleaseDir = project.ext.baseMetalsVerification.preparedReleaseDir -// Publishing is deliberately separate from building and remains guarded by explicit credentials. +// A normal build does not publish anything; publishing needs credentials. def mavenUploadUrl = providers.environmentVariable('MAVEN_UPLOAD_URL') .orElse('https://invalid.invalid/missing-maven-upload-url') def mavenUploadUsername = providers.environmentVariable('MAVEN_UPLOAD_USERNAME') diff --git a/gradle/verification/packaged-advancements.gradle b/gradle/verification/packaged-advancements.gradle new file mode 100644 index 00000000..1e71e858 --- /dev/null +++ b/gradle/verification/packaged-advancements.gradle @@ -0,0 +1,104 @@ +def runtime = project.ext.baseMetalsPackagedForge + +def probeJar = tasks.register('advancementRuntimeProbeJar', Jar) { + group = 'verification' + dependsOn tasks.named('testClasses') + archiveBaseName = 'basemetals-advancement-runtime-probe' + archiveVersion = '' + archiveClassifier = 'deobf' + destinationDirectory = layout.buildDirectory.dir('runtime-probes-dev') + from(sourceSets.test.output) { + include 'com/mcmoddev/basemetals/test/BaseMetalsAdvancementRuntimeProbe*.class' + } +} + +def packagedProbe = renamer.classes(probeJar) { + map.from minecraft.dependency.toSrgFile + archiveClassifier = null + output = layout.buildDirectory.file('runtime-probes/basemetals-advancement-runtime-probe.jar') +} + +// Each profile gets its own disposable world and configuration. +def profiles = [ + Enabled : '', + Disabled : 'general {\n B:achievements=false\n}\n', + MaterialOff: 'metals {\n B:EnableMithril=false\n}\n', + LowFantasy : 'general {\n S:contentMode=low_fantasy\n}\n' +] + +def qualification = tasks.register('packagedAdvancementsRuntimeTest') { + group = 'verification' + description = 'Checks gameplay achievements, save persistence, and configuration filtering.' +} + +profiles.each { profile, config -> + File runDirectory = layout.buildDirectory.dir("packaged-advancements-${profile.toLowerCase()}").get().asFile + File marker = new File(runDirectory, 'advancement-probe.properties') + def prepare = tasks.register("preparePackagedAdvancements${profile}") { + dependsOn runtime.releaseJar, packagedProbe, tasks.named('verifyReleaseDependencies') + doLast { + runtime.stagePackagedForgeBase(runDirectory) + File mods = new File(runDirectory, 'mods') + copy { + from layout.buildDirectory.file("libs/BaseMetals-${project.version}.jar") + from layout.buildDirectory.file('runtime-probes/basemetals-advancement-runtime-probe.jar') + from runtime.originalArtifact(configurations.legacyDependencyArtifacts, + runtime.dependencySpecs.mmdlib.coordinate) + from runtime.originalArtifact(configurations.legacyDependencyArtifacts, + runtime.dependencySpecs.orespawn4.coordinate) + into mods + } + if (config) { + File configFile = new File(runDirectory, 'config/BaseMetals.cfg') + configFile.parentFile.mkdirs() + configFile.setText(config, 'UTF-8') + } + } + } + def previous = prepare + ['Fresh', 'Reload'].each { phase -> + def dependency = previous + def process = tasks.register("packagedAdvancements${profile}${phase}", Exec) { + dependsOn dependency + workingDir runDirectory + ByteArrayOutputStream console = new ByteArrayOutputStream() + standardOutput = console + errorOutput = console + ignoreExitValue = true + doFirst { + console.reset() + marker.delete() + commandLine runtime.java8Launcher.get().executablePath.asFile, + '-Xmx2G', '-Dforge.logging.console.level=info', + "-Dbasemetals.advancementProbe.profile=${profile}", + "-Dbasemetals.advancementProbe.phase=${phase}", + "-Dbasemetals.advancementProbe.marker=${marker.absolutePath}", + '-jar', new File(runDirectory, + "forge-${project.minecraft_version}-${project.forge_version}-universal.jar"), + 'nogui' + } + doLast { + new File(runDirectory, "${phase.toLowerCase()}-console.txt") + .setText(console.toString('UTF-8'), 'UTF-8') + if (executionResult.get().exitValue != 0 || !marker.isFile()) { + throw new GradleException("${profile} ${phase} advancement probe failed; see ${runDirectory}") + } + Properties result = new Properties() + marker.withInputStream { result.load(it) } + if (result.getProperty('profile') != profile + || result.getProperty('phase') != phase + || result.getProperty('passed') != 'true') { + throw new GradleException("Invalid advancement probe result: ${result}") + } + def failures = runtime.runtimeLogFailures(runDirectory) + if (!failures.isEmpty()) { + throw new GradleException("${profile} ${phase} logged runtime errors: ${failures.take(10)}") + } + } + } + previous = process + } + qualification.configure { dependsOn previous } +} + +tasks.named('packagedForgeRuntimeTest') { dependsOn qualification } diff --git a/gradle/verification/packaged-forge-dependencies.gradle b/gradle/verification/packaged-forge-dependencies.gradle index 5542c1a3..beb2c4f2 100644 --- a/gradle/verification/packaged-forge-dependencies.gradle +++ b/gradle/verification/packaged-forge-dependencies.gradle @@ -9,7 +9,7 @@ def originalArtifact = packagedForge.originalArtifact def runtimeLogFailures = packagedForge.runtimeLogFailures def stagePackagedForgeBase = packagedForge.stagePackagedForgeBase -// These profiles prove that OreSpawn is required and that an existing explicit profile remains authoritative. +// Check that OreSpawn is required and saved worldgen overrides are preserved. File existingOverrideRun = file("${buildDir}/packaged-forge-existing-override-run") File existingOverrideMarker = new File(existingOverrideRun, 'basemetals-runtime-probe.properties') def prepareExistingOverride = tasks.register('preparePackagedForgeExistingOverrideRuntime') { diff --git a/gradle/verification/packaged-forge-tinkers.gradle b/gradle/verification/packaged-forge-tinkers.gradle index 3703e7b2..4c73ba3b 100644 --- a/gradle/verification/packaged-forge-tinkers.gradle +++ b/gradle/verification/packaged-forge-tinkers.gradle @@ -22,17 +22,7 @@ def tinkersCompatibilityProfiles = [ LowFantasy: [display: 'Tinkers Construct in Low Fantasy mode', taiga: false, prismarine: true, mode: 'low_fantasy'], LowFantasyConArm: [display: "Tinkers Construct and Construct's Armory in Low Fantasy mode", - taiga: false, conarm: true, prismarine: true, mode: 'low_fantasy'], - Realism: [display: 'Tinkers Construct in Realism mode', taiga: false, - prismarine: true, mode: 'realism'], - RealismConArm: [display: "Tinkers Construct and Construct's Armory in Realism mode", - taiga: false, conarm: true, prismarine: true, mode: 'realism'], - RealismExplicitOverride: [display: 'Realism with an explicit enabled OreSpawn override', - taiga: false, prismarine: true, mode: 'realism', preserveEnabledOres: true, - explicitOverride: true], - RealismExistingWorld: [display: 'a High Fantasy world restarted in Realism mode', - taiga: false, prismarine: true, mode: 'high_fantasy', reloadMode: 'realism', - preserveEnabledOres: true] + taiga: false, conarm: true, prismarine: true, mode: 'low_fantasy'] ] tinkersCompatibilityProfiles.each { profileName, profile -> @@ -119,17 +109,6 @@ tinkersCompatibilityProfiles.each { profileName, profile -> } new File(configDirectory, 'BaseMetals.cfg').setText(config.toString(), 'UTF-8') } - if (profile.explicitOverride) { - File configDirectory = new File(runDirectory, 'config') - configDirectory.mkdirs() - def explicitOverride = new JsonSlurper().parse( - file('docs/examples/basemetals-orespawn-disabled.json')) - explicitOverride.ores.each { id, rule -> rule.enabled = true } - new File(configDirectory, 'basemetals-orespawn.json').setText( - groovy.json.JsonOutput.prettyPrint( - groovy.json.JsonOutput.toJson(explicitOverride)) - + System.lineSeparator(), 'UTF-8') - } new File(runDirectory, 'server.properties').setText('''\ level-name=world level-seed=basemetals-tinkers-compatibility @@ -156,19 +135,6 @@ max-tick-time=-1 doFirst { console.reset() marker.delete() - String effectiveMode = phase == 'Reload' && profile.reloadMode - ? profile.reloadMode : profile.mode - if (phase == 'Reload' && profile.reloadMode) { - File configFile = new File(runDirectory, 'config/BaseMetals.cfg') - String configText = configFile.getText('UTF-8') - String changed = configText.replace( - 'S:contentMode=high_fantasy', - "S:contentMode=${profile.reloadMode}") - if (changed == configText) { - throw new GradleException("Could not change the existing-world content mode in ${configFile}") - } - configFile.setText(changed, 'UTF-8') - } File javaExecutable = java8Launcher.get().executablePath.asFile File forge = new File(runDirectory, "forge-${project.minecraft_version}-${project.forge_version}-universal.jar") @@ -178,7 +144,7 @@ max-tick-time=-1 "-Dbasemetals.probe.expectedTaiga=${profile.taiga}", "-Dbasemetals.probe.expectedConArm=${profile.conarm == true}", "-Dbasemetals.probe.expectedPrismarine=${profile.prismarine}", - "-Dbasemetals.probe.expectedContentMode=${effectiveMode}", + "-Dbasemetals.probe.expectedContentMode=${profile.mode}", "-Dbasemetals.probe.marker=${marker.absolutePath}", '-jar', forge, 'nogui' standardOutput = console @@ -193,14 +159,12 @@ max-tick-time=-1 } Properties result = new Properties() marker.withInputStream { result.load(it) } - String effectiveMode = phase == 'Reload' && profile.reloadMode - ? profile.reloadMode : profile.mode if (result.getProperty('phase') != phase.toLowerCase() || result.getProperty('registered') != 'true' || result.getProperty('taiga') != profile.taiga.toString() || result.getProperty('conarm') != (profile.conarm == true).toString() || result.getProperty('prismarine') != profile.prismarine.toString() - || result.getProperty('contentMode') != effectiveMode) { + || result.getProperty('contentMode') != profile.mode) { throw new GradleException("${profile.display} ${phase} probe result is invalid: ${result}") } File worldProfile = new File(runDirectory, @@ -214,15 +178,9 @@ max-tick-time=-1 } Set disabledRules = generatedRules.findAll { id, rule -> !rule.enabled } .keySet() as Set - Set expectedDisabledRules = !profile.preserveEnabledOres - && effectiveMode == 'realism' - ? ['basemetals:legacy/adamantine_ore', - 'basemetals:legacy/coldiron_ore', - 'basemetals:legacy/starsteel_ore'] as Set - : [] as Set - if (generatedRules.size() != 11 || disabledRules != expectedDisabledRules) { + if (generatedRules.size() != 11 || !disabledRules.isEmpty()) { throw new GradleException("${profile.display} loaded unexpected Base Metals rule defaults: " - + "disabled=${disabledRules}, expected=${expectedDisabledRules}") + + "disabled=${disabledRules}, expected=[]") } String latestLog = new File(runDirectory, 'logs/latest.log').getText('UTF-8') if (latestLog.contains('Fallback Ore Spawn Generator Enabled!') @@ -255,10 +213,6 @@ tasks.register('packagedForgeTinkersCompatibilityTest') { dependsOn tasks.named('packagedForgeTinkersPrismarineDisabledRuntimeTest') dependsOn tasks.named('packagedForgeTinkersLowFantasyRuntimeTest') dependsOn tasks.named('packagedForgeTinkersLowFantasyConArmRuntimeTest') - dependsOn tasks.named('packagedForgeTinkersRealismRuntimeTest') - dependsOn tasks.named('packagedForgeTinkersRealismConArmRuntimeTest') - dependsOn tasks.named('packagedForgeTinkersRealismExplicitOverrideRuntimeTest') - dependsOn tasks.named('packagedForgeTinkersRealismExistingWorldRuntimeTest') } tasks.named('packagedForgeRuntimeTest') { diff --git a/gradle/verification/packaged-forge.gradle b/gradle/verification/packaged-forge.gradle index 8a4aa0d3..21d4d056 100644 --- a/gradle/verification/packaged-forge.gradle +++ b/gradle/verification/packaged-forge.gradle @@ -137,6 +137,14 @@ def packagedStacks = [ extraMods: [], coordinate: dependencySpecs.orespawn4.coordinate ], + Os4NoPlateRepair: [ + display: 'OreSpawn 4 with plate repairs disabled', + modVersion: project.orespawn4_version, + expectedAncientWarfare: false, + disablePlateRepairs: true, + extraMods: [], + coordinate: dependencySpecs.orespawn4.coordinate + ], AncientWarfare: [ display: 'OreSpawn 4 plus Ancient Warfare 2', modVersion: project.orespawn4_version, @@ -216,6 +224,12 @@ spawn-protection=0 max-tick-time=-1 ''', 'UTF-8') new File(runDirectory, 'eula.txt').setText('eula=true\n', 'UTF-8') + if (stack.disablePlateRepairs) { + File configDirectory = new File(runDirectory, 'config') + configDirectory.mkdirs() + new File(configDirectory, 'MMDLib.cfg').setText( + 'general {\n B:repair_using_plates=false\n}\n', 'UTF-8') + } } } @@ -238,6 +252,7 @@ max-tick-time=-1 "-Dbasemetals.probe.phase=${phase.toLowerCase()}", "-Dbasemetals.probe.expectedOrespawn=${stack.modVersion}", "-Dbasemetals.probe.expectedAncientWarfare=${stack.expectedAncientWarfare}", + "-Dbasemetals.probe.expectPlateRepairs=${!stack.disablePlateRepairs}", "-Dbasemetals.probe.marker=${marker.absolutePath}", '-jar', forge, 'nogui' standardOutput = console @@ -300,6 +315,7 @@ tasks.register('packagedForgeRuntimeTest') { group = 'verification' description = 'Runs supported OreSpawn 4 fresh/reload packaged-server qualification.' dependsOn tasks.named('packagedForgeOs4RuntimeTest') + dependsOn tasks.named('packagedForgeOs4NoPlateRepairRuntimeTest') dependsOn tasks.named('packagedForgeAncientWarfareRuntimeTest') } @@ -370,3 +386,4 @@ apply from: 'gradle/verification/packaged-forge-dependencies.gradle' apply from: 'gradle/verification/packaged-forge-migration.gradle' apply from: 'gradle/verification/packaged-forge-cofh.gradle' apply from: 'gradle/verification/packaged-forge-tinkers.gradle' +apply from: 'gradle/verification/packaged-advancements.gradle' diff --git a/gradle/verification/support.gradle b/gradle/verification/support.gradle index aac89495..24b75d5a 100644 --- a/gradle/verification/support.gradle +++ b/gradle/verification/support.gradle @@ -9,7 +9,7 @@ def expectedMavenGroup = buildContract.mavenGroup def expectedMavenArtifact = buildContract.mavenArtifact def expectedMavenCoordinate = buildContract.mavenCoordinate -// Shared release checks belong here so every release-facing task uses one contract. +// Shared checks for release versions, toolchains, dependencies, and resources. def java8Launcher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(8) vendor = JvmVendorSpec.ADOPTIUM @@ -203,9 +203,11 @@ tasks.register('verifyReleaseDependencies') { tasks.register('verifyJsonResources') { group = 'verification' description = 'Parses every production JSON resource.' - inputs.files(fileTree('src/main/resources') { include '**/*.json' }) + dependsOn tasks.named('generateRecipeBookAdvancements'), tasks.named('generateGameplayAdvancements') + def productionJson = sourceSets.main.resources.matching { include '**/*.json' } + inputs.files(productionJson) doLast { - fileTree('src/main/resources') { include '**/*.json' }.files.sort().each { candidate -> + productionJson.files.toList().sort().each { candidate -> try { new JsonSlurper().parse(candidate) } catch (Exception failure) { diff --git a/gradle/verification/workflows.gradle b/gradle/verification/workflows.gradle index 65a2f5a1..41ca614b 100644 --- a/gradle/verification/workflows.gradle +++ b/gradle/verification/workflows.gradle @@ -1,4 +1,4 @@ -// Keep workflow validation close to the workflow contracts it protects. +// Check that the GitHub workflows still run the required build and release checks. tasks.register('verifyWorkflowContracts') { group = 'verification' description = 'Validates pinned CI, tag, and multi-target release-dispatcher contracts.' diff --git a/src/main/java/com/mcmoddev/basemetals/BaseMetals.java b/src/main/java/com/mcmoddev/basemetals/BaseMetals.java index 880f0323..87dfcc7e 100644 --- a/src/main/java/com/mcmoddev/basemetals/BaseMetals.java +++ b/src/main/java/com/mcmoddev/basemetals/BaseMetals.java @@ -25,15 +25,16 @@ /** Forge entry point for Base Metals. */ @Mod( - modid = BaseMetals.MODID, - name = BaseMetals.NAME, - version = BaseMetals.VERSION, - dependencies = "required-after:forge@[14.23.5.2859,);required-after:mmdlib;required-after:orespawn@[4.1.0.112021,5.0.0);after:tconstruct;after:conarm;after:thaumcraft;after:ic2;before:buildingbricks", - acceptedMinecraftVersions = "[1.12,1.12.2]", - certificateFingerprint = "", - updateJSON = BaseMetals.UPDATEJSON) + modid = BaseMetals.MODID, + name = BaseMetals.NAME, + version = BaseMetals.VERSION, + dependencies = "required-after:forge@[14.23.5.2859,);required-after:mmdlib;required-after:orespawn@[4.1.0.112021,5.0.0);after:tconstruct;after:conarm;after:thaumcraft;after:ic2;before:buildingbricks", + acceptedMinecraftVersions = "[1.12,1.12.2]", + guiFactory = "com.mcmoddev.basemetals.client.config.BaseMetalsGuiFactory", + certificateFingerprint = "", + updateJSON = BaseMetals.UPDATEJSON) public final class BaseMetals { - + @Instance public static BaseMetals instance; @@ -52,9 +53,8 @@ public final class BaseMetals { private static final String PROXY_BASE = SharedStrings.MMD_PROXY_GROUP + MODID + SharedStrings.DOT_PROXY_DOT; - @SidedProxy( - clientSide = PROXY_BASE + SharedStrings.CLIENTPROXY, - serverSide = PROXY_BASE + SharedStrings.SERVERPROXY) + @SidedProxy(clientSide = PROXY_BASE + SharedStrings.CLIENTPROXY, serverSide = PROXY_BASE + + SharedStrings.SERVERPROXY) public static CommonProxy proxy; public static final Logger logger = LogManager.getFormatterLogger(BaseMetals.MODID); @@ -93,6 +93,7 @@ public static void init(final FMLInitializationEvent event) { if (!BaseMetalsWorldgenProvider.enqueue()) { throw new IllegalStateException("OreSpawn rejected the Base Metals provider"); } + proxy.init(event); } @@ -100,7 +101,7 @@ public static void init(final FMLInitializationEvent event) { public static void postInit(final FMLPostInitializationEvent event) { proxy.postInit(event); } - + /** Restores historical block IDs when Forge loads an older save. */ @SubscribeEvent public void onRemapBlock(final RegistryEvent.MissingMappings event) { diff --git a/src/main/java/com/mcmoddev/basemetals/ModelDataFix.java b/src/main/java/com/mcmoddev/basemetals/ModelDataFix.java index c254e55b..cc1bba87 100755 --- a/src/main/java/com/mcmoddev/basemetals/ModelDataFix.java +++ b/src/main/java/com/mcmoddev/basemetals/ModelDataFix.java @@ -19,76 +19,85 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.registry.ForgeRegistries; -@Mod.EventBusSubscriber//(modid=BaseMetals.MODID) +@Mod.EventBusSubscriber public class ModelDataFix { private static List vanilla_names = Arrays.asList(MaterialNames.CHARCOAL, MaterialNames.COAL, - MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.ENDER, + MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.ENDER, MaterialNames.GOLD, MaterialNames.IRON, MaterialNames.LAPIS, MaterialNames.OBSIDIAN, MaterialNames.PRISMARINE, MaterialNames.QUARTZ, - MaterialNames.WOOD, MaterialNames.REDSTONE, MaterialNames.STONE, + MaterialNames.WOOD, MaterialNames.REDSTONE, MaterialNames.STONE, MaterialNames.REDSTONE); - + @SubscribeEvent public static void blockRegistryFix(RegistryEvent.MissingMappings ev) { ev.getAllMappings().stream() - .filter(mapping -> mapping.key.getNamespace().equalsIgnoreCase(MMDLib.MODID)) - .filter(mapping -> { - String[] pathBits = mapping.key.getPath().split("_"); - String matName = "double".equalsIgnoreCase(pathBits[0])?pathBits[1]:pathBits[0]; - return vanilla_names.contains(mapping.key.getPath().indexOf("_")!=-1?matName:mapping.key.getPath()) || "human_detector".equalsIgnoreCase(mapping.key.getPath()); - }) - .forEach(mapping -> { - BaseMetals.logger.fatal("mapping: {}", mapping.key); - if(mapping.key.getPath().indexOf("_") != -1) { - String p = mapping.key.getPath(); - int idx = mapping.key.getPath().indexOf("_"); - String materialName = p.substring(0, idx); - String blockName = p.substring(idx+1); - if("double".equals(materialName)) { - materialName = blockName.split("_")[0]; - blockName = Names.DOUBLE_SLAB.toString(); - } - mapping.remap(Materials.getMaterialByName(materialName).getBlock(blockName)); - } else { - mapping.remap(Materials.getMaterialByName(mapping.key.getPath()).getBlock("fluid")); - } - }); + .filter(mapping -> mapping.key.getNamespace().equalsIgnoreCase(MMDLib.MODID)) + .filter(mapping -> { + String[] pathBits = mapping.key.getPath().split("_"); + String matName = "double".equalsIgnoreCase(pathBits[0]) ? pathBits[1] : pathBits[0]; + + return vanilla_names + .contains(mapping.key.getPath().indexOf("_") != -1 ? matName : mapping.key.getPath()) + || "human_detector".equalsIgnoreCase(mapping.key.getPath()); + }) + .forEach(mapping -> { + BaseMetals.logger.fatal("mapping: {}", mapping.key); + + if (mapping.key.getPath().indexOf("_") != -1) { + String p = mapping.key.getPath(); + int idx = mapping.key.getPath().indexOf("_"); + String materialName = p.substring(0, idx); + String blockName = p.substring(idx + 1); + + if ("double".equals(materialName)) { + materialName = blockName.split("_")[0]; + blockName = Names.DOUBLE_SLAB.toString(); + } + + mapping.remap(Materials.getMaterialByName(materialName).getBlock(blockName)); + } else { + mapping.remap(Materials.getMaterialByName(mapping.key.getPath()).getBlock("fluid")); + } + }); } - + @SubscribeEvent public static void itemRegistryFix(RegistryEvent.MissingMappings ev) { ev.getAllMappings().stream() - .filter(mapping -> mapping.key.getNamespace().equalsIgnoreCase(MMDLib.MODID)) - .filter(mapping -> { - String[] pathBits = mapping.key.getPath().split("_"); - return vanilla_names.contains(mapping.key.getPath().indexOf("_")!=-1?pathBits[0]:mapping.key.getPath()); - }) - .forEach(mapping -> { - ResourceLocation remap = new ResourceLocation(BaseMetals.MODID, mapping.key.getPath()); - mapping.remap(ForgeRegistries.ITEMS.getValue(remap)); - }); + .filter(mapping -> mapping.key.getNamespace().equalsIgnoreCase(MMDLib.MODID)) + .filter(mapping -> { + String[] pathBits = mapping.key.getPath().split("_"); + + return vanilla_names + .contains(mapping.key.getPath().indexOf("_") != -1 ? pathBits[0] : mapping.key.getPath()); + }) + .forEach(mapping -> { + ResourceLocation remap = new ResourceLocation(BaseMetals.MODID, mapping.key.getPath()); + + mapping.remap(ForgeRegistries.ITEMS.getValue(remap)); + }); } - + @SubscribeEvent public static void materialRegistryFix(RegistryEvent.MissingMappings ev) { ev.getAllMappings().stream() - .filter(mapping -> mapping.key.getNamespace().equalsIgnoreCase(MMDLib.MODID)) - .filter(mapping -> vanilla_names.contains(mapping.key.getPath()) || - "default".equals(mapping.key.getPath()) || "empty".equals(mapping.key.getPath())) - .forEach(mapping -> mapping.remap(Materials.getMaterialByName(mapping.key.getPath()))); + .filter(mapping -> mapping.key.getNamespace().equalsIgnoreCase(MMDLib.MODID)) + .filter(mapping -> vanilla_names.contains(mapping.key.getPath()) || + "default".equals(mapping.key.getPath()) || "empty".equals(mapping.key.getPath())) + .forEach(mapping -> mapping.remap(Materials.getMaterialByName(mapping.key.getPath()))); } @SubscribeEvent public static void crusherRecipeRegistryFix(RegistryEvent.MissingMappings ev) { ev.getAllMappings().stream() - .filter(mapping -> mapping.key.getNamespace().equalsIgnoreCase(MMDLib.MODID)) - .forEach(mapping -> { - ResourceLocation remap = new ResourceLocation(BaseMetals.MODID, mapping.key.getPath()); - ICrusherRecipe recipeRemap = CrusherRecipeRegistry.getInstance().getRegistry().getValue(remap); - if(recipeRemap != null) { - mapping.remap(recipeRemap); - } - }); - } + .filter(mapping -> mapping.key.getNamespace().equalsIgnoreCase(MMDLib.MODID)) + .forEach(mapping -> { + ResourceLocation remap = new ResourceLocation(BaseMetals.MODID, mapping.key.getPath()); + ICrusherRecipe recipeRemap = CrusherRecipeRegistry.getInstance().getRegistry().getValue(remap); + if (recipeRemap != null) { + mapping.remap(recipeRemap); + } + }); + } } diff --git a/src/main/java/com/mcmoddev/basemetals/advancement/AchievementCondition.java b/src/main/java/com/mcmoddev/basemetals/advancement/AchievementCondition.java new file mode 100644 index 00000000..689dd5ab --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/advancement/AchievementCondition.java @@ -0,0 +1,29 @@ +package com.mcmoddev.basemetals.advancement; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.mcmoddev.lib.util.Config.Options; +import net.minecraft.item.Item; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.crafting.IConditionFactory; +import net.minecraftforge.common.crafting.JsonContext; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BooleanSupplier; + +/** Omits achievements whose settings or required items are disabled. */ +public final class AchievementCondition implements IConditionFactory { + + @Override + public BooleanSupplier parse(final JsonContext context, final JsonObject json) { + final List items = new ArrayList<>(); + + for (final JsonElement item : json.getAsJsonArray("items")) { + items.add(new ResourceLocation(item.getAsString())); + } + + return () -> Options.enableAchievements() + && items.stream().allMatch(Item.REGISTRY::containsKey); + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/advancement/GameplayAdvancements.java b/src/main/java/com/mcmoddev/basemetals/advancement/GameplayAdvancements.java new file mode 100644 index 00000000..63c00c9b --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/advancement/GameplayAdvancements.java @@ -0,0 +1,167 @@ +package com.mcmoddev.basemetals.advancement; + +import com.mcmoddev.basemetals.BaseMetals; +import com.mcmoddev.lib.util.Config.Options; +import net.minecraft.advancements.Advancement; +import net.minecraft.block.material.Material; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.item.ItemArmor; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.event.world.BlockEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.PlayerEvent.ItemCraftedEvent; +import net.minecraftforge.fml.common.gameevent.PlayerEvent.ItemSmeltedEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** Awards the original achievements for crafting, smelting, building, and equipment. */ +@EventBusSubscriber(modid = BaseMetals.MODID) +public final class GameplayAdvancements { + + private static final Set ALLOYS = new HashSet<>(Arrays.asList( + "aquarium", "brass", "bronze", "cupronickel", "electrum", "invar", + "mithril", "pewter", "steel")); + private static final EntityEquipmentSlot[] ARMOR_SLOTS = { + EntityEquipmentSlot.HEAD, EntityEquipmentSlot.CHEST, + EntityEquipmentSlot.LEGS, EntityEquipmentSlot.FEET}; + private static final String[] ARMOR_FORMS = {"helmet", "chestplate", "leggings", "boots"}; + + private GameplayAdvancements() { + } + + @SubscribeEvent + public static void crafted(final ItemCraftedEvent event) { + if (!enabled(event.player)) { + return; + } + + final String path = itemPath(event.crafting); + + if (path == null) { + return; + } + + if (path.endsWith("_crackhammer")) { + award(event.player, "geologist"); + } + + if (path.endsWith("_blend") || path.endsWith("_smallblend")) { + award(event.player, "metallurgy"); + } + } + + @SubscribeEvent + public static void smelted(final ItemSmeltedEvent event) { + if (!enabled(event.player)) { + return; + } + + final String path = itemPath(event.smelting); + + if (path == null || !path.endsWith("_ingot")) { + return; + } + + award(event.player, "this_is_new"); + + final String material = path.substring(0, path.length() - "_ingot".length()); + + if (ALLOYS.contains(material)) { + award(event.player, material + "_maker"); + } + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void placed(final BlockEvent.EntityPlaceEvent event) { + if (!(event.getEntity() instanceof EntityPlayerMP)) { + return; + } + + final EntityPlayerMP player = (EntityPlayerMP) event.getEntity(); + + if (!enabled(player)) { + return; + } + + final ResourceLocation id = event.getPlacedBlock().getBlock().getRegistryName(); + + if (id != null && BaseMetals.MODID.equals(id.getNamespace()) + && id.getPath().endsWith("_block") + && !"iron_block".equals(id.getPath()) && !"gold_block".equals(id.getPath())) { + award(player, "blocktastic"); + } + } + + @SubscribeEvent + public static void equipped(final TickEvent.PlayerTickEvent event) { + if (event.phase != TickEvent.Phase.END || !enabled(event.player) + || event.player.ticksExisted % 20 != 0) { + return; + } + + final EntityPlayer player = event.player; + + if (fullArmor(player, "adamantine")) { + award(player, "juggernaut"); + } + + if (fullArmor(player, "coldiron") && "coldiron_sword".equals(itemPath(player.getHeldItemMainhand()))) { + award(player, "demon_slayer"); + } + + if (fullArmor(player, "mithril") && "mithril_sword".equals(itemPath(player.getHeldItemMainhand()))) { + award(player, "angel_of_death"); + } + + if (fullArmor(player, "aquarium") && player.isInsideOfMaterial(Material.WATER)) { + award(player, "scuba_diver"); + } + + if ("starsteel_boots".equals(itemPath(player.getItemStackFromSlot(EntityEquipmentSlot.FEET)))) { + award(player, "moon_boots"); + } + } + + private static boolean enabled(final EntityPlayer player) { + return player instanceof EntityPlayerMP && !player.world.isRemote && Options.enableAchievements(); + } + + private static boolean fullArmor(final EntityPlayer player, final String material) { + for (int index = 0; index < ARMOR_SLOTS.length; index++) { + final ItemStack stack = player.getItemStackFromSlot(ARMOR_SLOTS[index]); + + if (!(stack.getItem() instanceof ItemArmor) + || ((ItemArmor) stack.getItem()).armorType != ARMOR_SLOTS[index] + || !(material + "_" + ARMOR_FORMS[index]).equals(itemPath(stack))) { + return false; + } + } + + return true; + } + + private static String itemPath(final ItemStack stack) { + final ResourceLocation id = stack.isEmpty() ? null : stack.getItem().getRegistryName(); + + return id != null && BaseMetals.MODID.equals(id.getNamespace()) ? id.getPath() : null; + } + + private static void award(final EntityPlayer player, final String id) { + final EntityPlayerMP serverPlayer = (EntityPlayerMP) player; + final Advancement advancement = player.getServer().getAdvancementManager() + .getAdvancement(new ResourceLocation(BaseMetals.MODID, id)); + + // Disabled achievements and server overrides may leave no definition to award. + if (advancement != null && !serverPlayer.getAdvancements().getProgress(advancement).isDone()) { + serverPlayer.getAdvancements().grantCriterion(advancement, "event"); + } + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen.java b/src/main/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen.java index fca4a297..975c7138 100644 --- a/src/main/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen.java +++ b/src/main/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreen.java @@ -22,7 +22,7 @@ import java.util.List; import java.util.Map; -/** Forge-native editor for the existing BaseMetals.cfg configuration. */ +/** Edits BaseMetals.cfg through Forge's configuration screen. */ public final class BaseMetalsConfigScreen extends GuiConfig implements GuiYesNoCallback { private static final int CONFIRM_CHANGES = 4701; @@ -45,63 +45,72 @@ public BaseMetalsConfigScreen(final GuiScreen parent) { static List categoryElements(final Configuration configuration) { final List elements = new ArrayList<>(); + for (final String categoryName : BMeConfig.GUI_CATEGORIES) { elements.add(new CategoryElement(configuration.getCategory(categoryName))); } + return elements; } static Map snapshot(final Configuration configuration) { final Map values = new LinkedHashMap<>(); + for (final String categoryName : BMeConfig.GUI_CATEGORIES) { final ConfigCategory category = configuration.getCategory(categoryName); + for (final Map.Entry property : category.getValues().entrySet()) { values.put(key(categoryName, property.getKey()), property.getValue().getString()); } } + return values; } static List disabledGeneratedRules(final Map before, final Configuration configuration) { final List disabled = new ArrayList<>(); + for (final Map.Entry generated : BMeConfig.getGeneratedOreRules().entrySet()) { final String propertyName = BMeConfig.getMaterialPropertyName(generated.getKey()); final String snapshotKey = key(BMeConfig.MATERIALS_CAT, propertyName); final Property property = configuration.getCategory(BMeConfig.MATERIALS_CAT) .get(propertyName); + if (Boolean.parseBoolean(before.get(snapshotKey)) && !property.getBoolean()) { disabled.add(generated.getValue()); } } + return disabled; } @Override protected void actionPerformed(final GuiButton button) { if (button.id == 2000 && entryList.hasChangedEntry(true)) { - // Child category entries retain their pending values until the root Done - // action. Apply them temporarily so the material/OreSpawn relationship - // can be checked, then restore the backing Configuration while the - // confirmation is open. + // Read the pending category edits to check whether a warning is needed. + // Restore the original values while the player decides whether to save. + entryList.saveConfigElements(); + final ContentMode initialMode = ContentMode.fromSerializedName(initialValues.get( key(BMeConfig.GENERAL_CAT, BMeConfig.CONTENT_MODE_PROPERTY))); final ContentMode selectedMode = BMeConfig.configuredContentMode(configuration); final List disabledRules = disabledGeneratedRules(initialValues, configuration); + if (initialMode != selectedMode || !disabledRules.isEmpty()) { restoreInitialValues(); pendingDoneButton = button; + final String title; String message; + if (initialMode != selectedMode) { title = I18n.format("config.basemetals.warning.content_mode.title"); - final String detailKey = selectedMode == ContentMode.REALISM - ? "config.basemetals.warning.content_mode.realism" - : "config.basemetals.warning.content_mode.message"; - message = I18n.format(detailKey, + message = I18n.format("config.basemetals.warning.content_mode.message", I18n.format(initialMode.translationKey()), I18n.format(selectedMode.translationKey())); + if (!disabledRules.isEmpty()) { message += "\n\n" + I18n.format( "config.basemetals.warning.disable_ores.message", @@ -112,13 +121,16 @@ protected void actionPerformed(final GuiButton button) { message = I18n.format("config.basemetals.warning.disable_ores.message", String.join(", ", disabledRules)); } + mc.displayGuiScreen(new GuiYesNo(this, title, message, I18n.format("config.basemetals.warning.confirm"), I18n.format("gui.cancel"), CONFIRM_CHANGES)); + return; } } + super.actionPerformed(button); } @@ -127,10 +139,13 @@ public void confirmClicked(final boolean result, final int id) { if (id != CONFIRM_CHANGES) { return; } + mc.displayGuiScreen(this); + if (result && pendingDoneButton != null) { super.actionPerformed(pendingDoneButton); } + pendingDoneButton = null; } @@ -140,8 +155,10 @@ protected void keyTyped(final char eventChar, final int eventKey) { entryList.undoAllChanges(true); restoreInitialValues(); mc.displayGuiScreen(parentScreen); + return; } + super.keyTyped(eventChar, eventKey); } @@ -153,8 +170,10 @@ static void restore(final Map values, final Configuration configuration) { for (final String categoryName : BMeConfig.GUI_CATEGORIES) { final ConfigCategory category = configuration.getCategory(categoryName); + for (final Map.Entry property : category.getValues().entrySet()) { final String value = values.get(key(categoryName, property.getKey())); + if (value != null) { property.getValue().set(value); } @@ -177,7 +196,7 @@ public Class getConfigEntryClass() { } } - /** Category button that creates an Escape-safe child configuration page. */ + /** Opens a category page that lets Escape cancel its edits. */ public static final class CategoryEntry extends GuiConfigEntries.CategoryEntry { public CategoryEntry(final GuiConfig owningScreen, final GuiConfigEntries owningEntryList, @@ -197,7 +216,7 @@ protected GuiScreen buildChildScreen() { } } - /** Nested page whose Escape action truly discards that page's edits. */ + /** Cancels unsaved edits when the player presses Escape. */ public static final class CategoryScreen extends GuiConfig { CategoryScreen(final GuiScreen parent, final List elements, final String modId, final boolean requiresWorldRestart, @@ -212,8 +231,10 @@ protected void keyTyped(final char eventChar, final int eventKey) { if (eventKey == Keyboard.KEY_ESCAPE) { entryList.undoAllChanges(true); mc.displayGuiScreen(parentScreen); + return; } + super.keyTyped(eventChar, eventKey); } } diff --git a/src/main/java/com/mcmoddev/basemetals/client/config/BaseMetalsGuiFactory.java b/src/main/java/com/mcmoddev/basemetals/client/config/BaseMetalsGuiFactory.java new file mode 100644 index 00000000..9bee92d4 --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/client/config/BaseMetalsGuiFactory.java @@ -0,0 +1,32 @@ +package com.mcmoddev.basemetals.client.config; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import net.minecraftforge.fml.client.IModGuiFactory; + +import java.util.Collections; +import java.util.Set; + +/** Opens the existing configuration screen from Forge's Mods list. */ +public final class BaseMetalsGuiFactory implements IModGuiFactory { + + @Override + public void initialize(final Minecraft minecraftInstance) { + // The screen uses the configuration already loaded by Base Metals. + } + + @Override + public boolean hasConfigGui() { + return true; + } + + @Override + public GuiScreen createConfigGui(final GuiScreen parentScreen) { + return new BaseMetalsConfigScreen(parentScreen); + } + + @Override + public Set runtimeGuiCategories() { + return Collections.emptySet(); + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/client/renderer/RenderBaseMetalsBolt.java b/src/main/java/com/mcmoddev/basemetals/client/renderer/RenderBaseMetalsBolt.java index 4736117d..d7704754 100644 --- a/src/main/java/com/mcmoddev/basemetals/client/renderer/RenderBaseMetalsBolt.java +++ b/src/main/java/com/mcmoddev/basemetals/client/renderer/RenderBaseMetalsBolt.java @@ -9,24 +9,15 @@ import net.minecraftforge.fml.relauncher.SideOnly; /** - * Renders MMDLib bolts with Minecraft's existing projectile texture. - * - *

MMDLib requests {@code minecraft:textures/entity/projectiles/bolt.png}, - * which does not exist in Minecraft 1.12.2. The bolt and arrow renderers use - * the same geometry and UV layout, so the vanilla arrow texture is the - * compatible replacement.

+ * Uses the vanilla arrow texture for bolts; MMDLib's bolt texture does not exist. + * The two projectiles share the same model and texture layout. */ @SideOnly(Side.CLIENT) public final class RenderBaseMetalsBolt extends RenderCustomBolt { - private static final ResourceLocation PROJECTILE_TEXTURE = - new ResourceLocation("minecraft", "textures/entity/projectiles/arrow.png"); + private static final ResourceLocation PROJECTILE_TEXTURE = new ResourceLocation("minecraft", + "textures/entity/projectiles/arrow.png"); - /** - * Creates the Base Metals bolt renderer. - * - * @param renderManager Minecraft's entity render manager - */ public RenderBaseMetalsBolt(final RenderManager renderManager) { super(renderManager); } diff --git a/src/main/java/com/mcmoddev/basemetals/content/ContentMode.java b/src/main/java/com/mcmoddev/basemetals/content/ContentMode.java index 36736033..45d795e5 100644 --- a/src/main/java/com/mcmoddev/basemetals/content/ContentMode.java +++ b/src/main/java/com/mcmoddev/basemetals/content/ContentMode.java @@ -2,11 +2,10 @@ import java.util.Locale; -/** Stable content-policy modes stored in {@code BaseMetals.cfg} and sent over the network. */ +/** Content modes, with names shared by the config file and network messages. */ public enum ContentMode { HIGH_FANTASY("high_fantasy"), - LOW_FANTASY("low_fantasy"), - REALISM("realism"); + LOW_FANTASY("low_fantasy"); private final String serializedName; @@ -25,12 +24,14 @@ public String translationKey() { public static ContentMode fromSerializedName(final String value) { if (value != null) { final String normalized = value.trim().toLowerCase(Locale.ROOT); + for (final ContentMode mode : values()) { if (mode.serializedName.equals(normalized)) { return mode; } } } + return HIGH_FANTASY; } @@ -38,29 +39,35 @@ public static boolean isValidSerializedName(final String value) { if (value == null) { return false; } + for (final ContentMode mode : values()) { if (mode.serializedName.equals(value.trim().toLowerCase(Locale.ROOT))) { return true; } } + return false; } public static String[] serializedNames() { final ContentMode[] modes = values(); final String[] names = new String[modes.length]; + for (int i = 0; i < modes.length; i++) { names[i] = modes[i].serializedName; } + return names; } public static String[] translationKeys() { final ContentMode[] modes = values(); final String[] names = new String[modes.length]; + for (int i = 0; i < modes.length; i++) { names[i] = modes[i].translationKey(); } + return names; } } diff --git a/src/main/java/com/mcmoddev/basemetals/content/ContentPolicy.java b/src/main/java/com/mcmoddev/basemetals/content/ContentPolicy.java index 9ef40eb9..9542937c 100644 --- a/src/main/java/com/mcmoddev/basemetals/content/ContentPolicy.java +++ b/src/main/java/com/mcmoddev/basemetals/content/ContentPolicy.java @@ -11,7 +11,7 @@ import java.util.Locale; import java.util.Set; -/** Immutable, reviewed material-by-form acquisition policy. */ +/** Defines which material forms can be made in each content mode. */ public final class ContentPolicy { private static final Set MATERIALS = set( MaterialNames.ADAMANTINE, MaterialNames.ANTIMONY, MaterialNames.AQUARIUM, @@ -27,10 +27,6 @@ public final class ContentPolicy { MaterialNames.STARSTEEL, MaterialNames.STEEL, MaterialNames.STONE, MaterialNames.TIN, MaterialNames.WOOD, MaterialNames.ZINC); - private static final Set MYTHICAL = set(MaterialNames.ADAMANTINE, - MaterialNames.AQUARIUM, MaterialNames.COLDIRON, MaterialNames.MITHRIL, - MaterialNames.STARSTEEL); - private static final Set FULL_TOOLS = set(MaterialNames.ADAMANTINE, MaterialNames.AQUARIUM, MaterialNames.BRONZE, MaterialNames.COLDIRON, MaterialNames.COPPER, MaterialNames.CUPRONICKEL, MaterialNames.INVAR, @@ -91,49 +87,53 @@ public ContentMode mode() { return mode; } - public boolean allowsMaterial(final String material) { - return mode != ContentMode.REALISM || !MYTHICAL.contains(normalize(material)); - } - public boolean allows(final String material, final MaterialForm form) { final String name = normalize(material); + if (mode == ContentMode.HIGH_FANTASY || material == null || form == null) { return true; } - if (!allowsMaterial(name)) { - return false; - } + if (form == MaterialForm.OTHER) { return !MaterialNames.MERCURY.equals(name); } + if (form == MaterialForm.BOW || form == MaterialForm.CROSSBOW || form == MaterialForm.FISHING_ROD) { return false; } + if (TOOLS.contains(form)) { return allowsTool(name, form); } + if (ARMOR_FORMS.contains(form)) { return PROTECTIVE.contains(name); } + if (form == MaterialForm.ARROW || form == MaterialForm.BOLT) { return AMMUNITION.contains(name); } + if (form == MaterialForm.GEAR) { return GEARS.contains(name); } + if (form == MaterialForm.ANVIL) { return MaterialNames.STONE.equals(name) || MaterialNames.STEEL.equals(name) - || (mode == ContentMode.LOW_FANTASY && MaterialNames.ADAMANTINE.equals(name)); + || MaterialNames.ADAMANTINE.equals(name); } + if (MaterialNames.MERCURY.equals(name)) { return form == MaterialForm.ORE || form == MaterialForm.POWDER || form == MaterialForm.SMALLPOWDER || form == MaterialForm.FLUID - || (mode == ContentMode.LOW_FANTASY && form == MaterialForm.INGOT); + || form == MaterialForm.INGOT; } + if (BUILDING_FORMS.contains(form)) { return true; } + return true; } @@ -141,6 +141,7 @@ public boolean allows(final ItemStack stack) { if (stack == null || stack.isEmpty() || stack.getItem().getRegistryName() == null) { return true; } + return allows(stack.getItem().getRegistryName()); } @@ -148,62 +149,68 @@ public boolean allows(final ResourceLocation id) { if (id == null || !BaseMetals.MODID.equals(id.getNamespace())) { return true; } + final String material = materialFromPath(id.getPath()); + if (material == null) { return true; } + MaterialForm form = MaterialForm.fromRegistryPath(id.getPath()); + if (form == MaterialForm.OTHER && id.getPath().equals(material)) { form = MaterialForm.FLUID; } + return allows(material, form); } - /** Resolves a recipe ID when a dynamic recipe has no representative output stack. */ + /** Checks the recipe name when a dynamic recipe has no fixed output. */ public boolean allowsRecipeId(final ResourceLocation recipeId) { if (recipeId == null || !BaseMetals.MODID.equals(recipeId.getNamespace())) { return true; } + final String material = materialFromPath(recipeId.getPath()); + if (material == null) { return true; } + final String path = recipeId.getPath(); String remainder = path.startsWith("double_" + material + "_") ? path.substring(("double_" + material + "_").length()) : path.equals(material) ? "" : path.substring((material + "_").length()); MaterialForm form = MaterialForm.fromRegistryPath(path); + if (form == MaterialForm.OTHER) { for (final MaterialForm candidate : MaterialForm.values()) { final String token = candidate.name().toLowerCase(Locale.ROOT); + if (remainder.equals(token) || remainder.startsWith(token + "_")) { form = candidate; break; } } } - return allows(material, form); - } - public boolean defaultsOreEnabled(final String material) { - return mode != ContentMode.REALISM || !MYTHICAL.contains(normalize(material)); - } - - public static boolean isMythical(final String material) { - return MYTHICAL.contains(normalize(material)); + return allows(material, form); } public static String materialFromPath(final String registryPath) { if (registryPath == null) { return null; } + final String path = registryPath.toLowerCase(Locale.ROOT); + for (final String material : MATERIALS) { if (path.equals(material) || path.startsWith(material + "_") || path.startsWith("double_" + material + "_")) { return material; } } + return null; } @@ -211,20 +218,25 @@ private boolean allowsTool(final String material, final MaterialForm form) { if (FULL_TOOLS.contains(material)) { return true; } + if (MaterialNames.SILVER.equals(material)) { return form == MaterialForm.SWORD; } + if (MaterialNames.OBSIDIAN.equals(material)) { return form == MaterialForm.AXE || form == MaterialForm.SWORD || form == MaterialForm.SCYTHE; } + if (MaterialNames.DIAMOND.equals(material)) { return form == MaterialForm.CRACKHAMMER || form == MaterialForm.SCYTHE || form == MaterialForm.SHEARS; } + if (MaterialNames.STONE.equals(material)) { return form == MaterialForm.CRACKHAMMER || form == MaterialForm.SCYTHE; } + return MaterialNames.WOOD.equals(material) && form == MaterialForm.CRACKHAMMER; } @@ -238,7 +250,9 @@ private static Set set(final String... values) { private static Set union(final Set first, final Set second) { final Set values = new LinkedHashSet<>(first); + values.addAll(second); + return Collections.unmodifiableSet(values); } } diff --git a/src/main/java/com/mcmoddev/basemetals/content/MaterialForm.java b/src/main/java/com/mcmoddev/basemetals/content/MaterialForm.java index 1287ac53..fc468fb8 100644 --- a/src/main/java/com/mcmoddev/basemetals/content/MaterialForm.java +++ b/src/main/java/com/mcmoddev/basemetals/content/MaterialForm.java @@ -2,7 +2,7 @@ import java.util.Locale; -/** Form families used by the content policy. Registry identities are never removed. */ +/** Item and block forms used to decide which recipes a content mode permits. */ public enum MaterialForm { ARROW, AXE, @@ -62,24 +62,29 @@ public enum MaterialForm { FLUID, OTHER; - /** Resolves the conventional suffix used by Base Metals and MMDLib registry IDs. */ + /** Finds the form from the suffix of a Base Metals or MMDLib registry name. */ public static MaterialForm fromRegistryPath(final String registryPath) { if (registryPath == null) { return OTHER; } + final String path = registryPath.toLowerCase(Locale.ROOT); MaterialForm match = OTHER; int longestMatch = -1; + for (final MaterialForm form : values()) { if (form == OTHER || form == FLUID) { continue; } + final String suffix = registrySuffix(form); + if (path.endsWith("_" + suffix) && suffix.length() > longestMatch) { match = form; longestMatch = suffix.length(); } } + return match; } @@ -87,6 +92,7 @@ private static String registrySuffix(final MaterialForm form) { if (form == DIRTY_POWDER) { return "powder_dirty"; } + return form.name().toLowerCase(Locale.ROOT); } } diff --git a/src/main/java/com/mcmoddev/basemetals/init/Blocks.java b/src/main/java/com/mcmoddev/basemetals/init/Blocks.java index ceca912b..56d6db8a 100644 --- a/src/main/java/com/mcmoddev/basemetals/init/Blocks.java +++ b/src/main/java/com/mcmoddev/basemetals/init/Blocks.java @@ -22,7 +22,7 @@ import net.minecraftforge.registries.IForgeRegistry; /** Creates and registers Base Metals blocks. */ -@Mod.EventBusSubscriber(modid=BaseMetals.MODID) +@Mod.EventBusSubscriber(modid = BaseMetals.MODID) public final class Blocks extends com.mcmoddev.lib.init.Blocks { private Blocks() { @@ -78,7 +78,9 @@ private static void createAnvils() { private static void createMercury() { if (Materials.hasMaterial(MaterialNames.MERCURY)) { final MMDMaterial mercury = Materials.getMaterialByName(MaterialNames.MERCURY); + create(Names.ORE, mercury); + if (mercury.hasBlock(Names.ORE)) { mercury.getBlock(Names.ORE).setHardness(3.0f).setResistance(5.0f); } @@ -98,6 +100,6 @@ private static void regBlocks(final IForgeRegistry registry, final ImmutableList blocks) { blocks.stream().filter( block -> block.getRegistryName().getNamespace().equals(BaseMetals.MODID)) - .forEach( registry::register ); + .forEach(registry::register); } } diff --git a/src/main/java/com/mcmoddev/basemetals/init/Fluids.java b/src/main/java/com/mcmoddev/basemetals/init/Fluids.java index c53a705d..a9acdc35 100644 --- a/src/main/java/com/mcmoddev/basemetals/init/Fluids.java +++ b/src/main/java/com/mcmoddev/basemetals/init/Fluids.java @@ -14,7 +14,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; /** Creates Base Metals fluids and their blocks. */ -@Mod.EventBusSubscriber(modid=BaseMetals.MODID) +@Mod.EventBusSubscriber(modid = BaseMetals.MODID) public final class Fluids extends com.mcmoddev.lib.init.Fluids { private Fluids() { diff --git a/src/main/java/com/mcmoddev/basemetals/init/Items.java b/src/main/java/com/mcmoddev/basemetals/init/Items.java index a07365a0..a4b44b7f 100644 --- a/src/main/java/com/mcmoddev/basemetals/init/Items.java +++ b/src/main/java/com/mcmoddev/basemetals/init/Items.java @@ -28,7 +28,7 @@ import net.minecraftforge.registries.IForgeRegistry; /** Creates and registers Base Metals items. */ -@Mod.EventBusSubscriber(modid=BaseMetals.MODID) +@Mod.EventBusSubscriber(modid = BaseMetals.MODID) public final class Items extends com.mcmoddev.lib.init.Items { private Items() { @@ -48,7 +48,7 @@ public static void registerItems(MMDLibRegisterItems ev) { MaterialNames.SILVER, MaterialNames.STARSTEEL, MaterialNames.STEEL, MaterialNames.TIN, MaterialNames.ZINC); - // These materials expose the extended processing forms used by integration mods. + // These materials need extra forms for other mods' ore-processing chains. final List materialsModSupport = Arrays.asList(MaterialNames.ADAMANTINE, MaterialNames.ANTIMONY, MaterialNames.BISMUTH, MaterialNames.COLDIRON, MaterialNames.PLATINUM, MaterialNames.NICKEL, MaterialNames.STARSTEEL, @@ -137,7 +137,7 @@ public static void registerItems(final RegistryEvent.Register event) { Materials.getAllMaterials() .stream() .filter(mat -> !mat.isVanilla()) - .forEach(mat -> regItems(event.getRegistry(), mat.getItems())); + .forEach(mat -> regItems(event.getRegistry(), mat.getItems())); Oredicts.registerItemOreDictionaryEntries(); Oredicts.registerBlockOreDictionaryEntries(); @@ -148,6 +148,7 @@ private static void applyFishingRodDurability() { .filter(material -> material.hasItem(Names.FISHING_ROD)) .forEach(material -> { final Item fishingRod = material.getItem(Names.FISHING_ROD); + if (fishingRod.getRegistryName() != null && BaseMetals.MODID.equals(fishingRod.getRegistryName().getNamespace())) { fishingRod.setMaxDamage(material.getToolDurability()); @@ -156,88 +157,93 @@ private static void applyFishingRodDurability() { } /** - * Creates a Base Metals-owned arrow whose material contributes to damage. + * Gets or creates a material arrow. * - * @param material material used to construct the arrow * @return the existing or newly created arrow, or {@code null} when disabled */ public static Item createArrow(final MMDMaterial material) { if (material.hasItem(Names.ARROW)) { return material.getItem(Names.ARROW); } + if (!isNameEnabled(Names.ARROW)) { return null; } + return registerRangedItem(Names.ARROW, material, new ItemBaseMetalsArrow(material)); } /** - * Creates a Base Metals-owned bolt whose material contributes to damage. + * Gets or creates a material bolt. * - * @param material material used to construct the bolt * @return the existing or newly created bolt, or {@code null} when disabled */ public static Item createBolt(final MMDMaterial material) { if (material.hasItem(Names.BOLT)) { return material.getItem(Names.BOLT); } + if (!isNameEnabled(Names.BOLT)) { return null; } + return registerRangedItem(Names.BOLT, material, new ItemBaseMetalsBolt(material)); } /** - * Creates a Base Metals-owned bow whose material contributes to damage. + * Gets or creates a material bow. * - * @param material material used to construct the bow * @return the existing or newly created bow, or {@code null} when disabled */ public static Item createBow(final MMDMaterial material) { if (material.hasItem(Names.BOW)) { return material.getItem(Names.BOW); } + if (!isNameEnabled(Names.BOW)) { return null; } + return registerRangedItem(Names.BOW, material, new ItemBaseMetalsBow(material)); } /** - * Creates a Base Metals-owned crossbow with the corrected server-side bolt - * firing behavior while preserving MMDLib's material and registry contracts. + * Gets or creates a crossbow that fires bolts on the server. * - * @param material material used to construct the crossbow * @return the existing or newly created crossbow, or {@code null} when disabled */ public static Item createCrossbow(final MMDMaterial material) { if (material.hasItem(Names.CROSSBOW)) { return material.getItem(Names.CROSSBOW); } + if (!isNameEnabled(Names.CROSSBOW)) { return null; } + return registerRangedItem(Names.CROSSBOW, material, new ItemBaseMetalsCrossbow(material)); } /** - * Creates a Base Metals-owned hoe which preserves ItemHoe's material-name - * contract for compatibility with other mods. + * Gets or creates a hoe with a vanilla-compatible tool-material name. * - * @param material material used to construct the hoe * @return the existing or newly created hoe, or {@code null} when disabled */ public static Item createHoe(final MMDMaterial material) { if (material.hasItem(Names.HOE)) { return material.getItem(Names.HOE); } + if (!isNameEnabled(Names.HOE)) { return null; } + final Item registered = addItem(new ItemBaseMetalsHoe(material), Names.HOE.toString(), material, ItemGroups.getTab(SharedStrings.TAB_TOOLS)); + material.addNewItem(Names.HOE, registered); + return registered; } @@ -245,14 +251,16 @@ private static Item registerRangedItem(final Names name, final MMDMaterial mater final Item item) { final Item registered = addItem(item, name.toString(), material, ItemGroups.getTab(SharedStrings.TAB_COMBAT)); + material.addNewItem(name, registered); + return registered; } private static void regItems(final IForgeRegistry registry, final ImmutableList items) { items.stream().filter(Items::isThisMod).map(Items::getItem) - .forEach( registry::register ); + .forEach(registry::register); } private static Item getItem(final ItemStack it) { diff --git a/src/main/java/com/mcmoddev/basemetals/init/Materials.java b/src/main/java/com/mcmoddev/basemetals/init/Materials.java index 1a6f599f..f2716d85 100644 --- a/src/main/java/com/mcmoddev/basemetals/init/Materials.java +++ b/src/main/java/com/mcmoddev/basemetals/init/Materials.java @@ -55,21 +55,21 @@ public static void init(final MMDLibRegisterMaterials event) { rareAlloyMaterials.stream().filter(Options::isMaterialEnabled).forEach(name -> createRareAlloyMaterial(name, MaterialType.METAL, getHardness(name), getStrength(name), getMagic(name), getColor(name))); - - if(Options.isMaterialEnabled(MaterialNames.MERCURY)) { + + if (Options.isMaterialEnabled(MaterialNames.MERCURY)) { createMaterial(MaterialNames.MERCURY, MaterialType.METAL, 1.0d, 1.0d, 1.0d, 0xFFE2E2E2, true); Materials.getMaterialByName(MaterialNames.MERCURY).setFluidBlockGetter(new IFluidBlockGetter() { public BlockFluidClassic apply(String fluidName) { return new InteractiveFluidBlock(FluidRegistry.getFluid(MaterialNames.MERCURY), false, - (final World w, final EntityLivingBase e) -> { - if (w.rand.nextInt(32) == 0) { - e.addPotionEffect(new PotionEffect(MobEffects.NAUSEA, 30 * 20, 2)); - } - }); + (final World w, final EntityLivingBase e) -> { + if (w.rand.nextInt(32) == 0) { + e.addPotionEffect(new PotionEffect(MobEffects.NAUSEA, 30 * 20, 2)); + } + }); } }); } - + // Rare metals retain their historical blast resistance and dimension hints. if (hasMaterial(MaterialNames.ADAMANTINE)) { getMaterialByName(MaterialNames.ADAMANTINE).setBlastResistance(2000f).setSpawnSize(4) @@ -84,181 +84,181 @@ public BlockFluidClassic apply(String fluidName) { public static void initTooltips() { Arrays.asList(MaterialNames.ADAMANTINE, MaterialNames.COLDIRON, MaterialNames.AQUARIUM, MaterialNames.MITHRIL) - .stream().filter(Options::isMaterialEnabled) - .forEach(mn -> { - Arrays.asList(Names.HELMET, Names.CHESTPLATE, Names.LEGGINGS, Names.BOOTS).stream() - .forEach(n -> Materials.getMaterialByName(mn) - .addTooltipFor(n, BMEPropertiesHelper.addArmorSpecialPropertiesToolTip(mn))); - Arrays.asList(Names.values()).stream() - .filter(n -> (n != Names.HELMET && n != Names.CHESTPLATE && n != Names.LEGGINGS && n != Names.BOOTS)) - .forEach(n -> Materials.getMaterialByName(mn) - .addTooltipFor(n, BMEPropertiesHelper.addToolSpecialPropertiesToolTip(mn))); - }); + .stream().filter(Options::isMaterialEnabled) + .forEach(mn -> { + Arrays.asList(Names.HELMET, Names.CHESTPLATE, Names.LEGGINGS, Names.BOOTS).stream() + .forEach(n -> Materials.getMaterialByName(mn) + .addTooltipFor(n, BMEPropertiesHelper.addArmorSpecialPropertiesToolTip(mn))); + Arrays.asList(Names.values()).stream() + .filter(n -> (n != Names.HELMET && n != Names.CHESTPLATE && n != Names.LEGGINGS + && n != Names.BOOTS)) + .forEach(n -> Materials.getMaterialByName(mn) + .addTooltipFor(n, BMEPropertiesHelper.addToolSpecialPropertiesToolTip(mn))); + }); } - + private static int getColor(@Nonnull final String name) { switch (name) { - case MaterialNames.ADAMANTINE: + case MaterialNames.ADAMANTINE : return 0xFF53393F; - case MaterialNames.ANTIMONY: + case MaterialNames.ANTIMONY : return 0xFFD8E3DE; - case MaterialNames.AQUARIUM: + case MaterialNames.AQUARIUM : return 0xFF0000FF; - case MaterialNames.BISMUTH: + case MaterialNames.BISMUTH : return 0xFFDDD7CB; - case MaterialNames.BRASS: + case MaterialNames.BRASS : return 0xFFFFE374; - case MaterialNames.BRONZE: + case MaterialNames.BRONZE : return 0xFFF7A54F; - case MaterialNames.COLDIRON: + case MaterialNames.COLDIRON : return 0xFFC7CEF0; - case MaterialNames.COPPER: + case MaterialNames.COPPER : return 0xFFFF9F78; - case MaterialNames.CUPRONICKEL: + case MaterialNames.CUPRONICKEL : return 0xFFC8AB6F; - case MaterialNames.ELECTRUM: + case MaterialNames.ELECTRUM : return 0xFFFFF2B3; - case MaterialNames.INVAR: + case MaterialNames.INVAR : return 0xFFD2CDB8; - case MaterialNames.LEAD: + case MaterialNames.LEAD : return 0xFF7B7B7B; - case MaterialNames.MITHRIL: + case MaterialNames.MITHRIL : return 0xFFF4FFFF; - case MaterialNames.NICKEL: + case MaterialNames.NICKEL : return 0xFFEEFFEB; - case MaterialNames.PEWTER: + case MaterialNames.PEWTER : return 0xFF92969F; - case MaterialNames.PLATINUM: + case MaterialNames.PLATINUM : return 0xFFF2FFFF; - case MaterialNames.SILVER: + case MaterialNames.SILVER : return 0xFFFFFFFF; - case MaterialNames.STARSTEEL: + case MaterialNames.STARSTEEL : return 0xFF53393F; - case MaterialNames.STEEL: + case MaterialNames.STEEL : return 0xFFD5E3E5; - case MaterialNames.TIN: + case MaterialNames.TIN : return 0xFFFFF7EE; - case MaterialNames.ZINC: + case MaterialNames.ZINC : return 0xFFBCBCBC; - default: + default : return 0x00000000; } } private static double getMagic(@Nonnull final String name) { switch (name) { - case MaterialNames.PLATINUM: - case MaterialNames.AQUARIUM: + case MaterialNames.PLATINUM : + case MaterialNames.AQUARIUM : return 15.0d; - case MaterialNames.STARSTEEL: + case MaterialNames.STARSTEEL : return 12.0d; - case MaterialNames.ELECTRUM: + case MaterialNames.ELECTRUM : return 10.0d; - case MaterialNames.MITHRIL: - case MaterialNames.BRASS: + case MaterialNames.MITHRIL : + case MaterialNames.BRASS : return 9.0d; - case MaterialNames.NICKEL: - case MaterialNames.COLDIRON: + case MaterialNames.NICKEL : + case MaterialNames.COLDIRON : return 7.0d; - case MaterialNames.SILVER: - case MaterialNames.CUPRONICKEL: + case MaterialNames.SILVER : + case MaterialNames.CUPRONICKEL : return 6.0d; - case MaterialNames.COPPER: + case MaterialNames.COPPER : return 5.0d; - case MaterialNames.BRONZE: + case MaterialNames.BRONZE : return 4.5d; - case MaterialNames.INVAR: + case MaterialNames.INVAR : return 3.0d; - case MaterialNames.TIN: - case MaterialNames.STEEL: + case MaterialNames.TIN : + case MaterialNames.STEEL : return 2.0d; - case MaterialNames.ANTIMONY: - case MaterialNames.BISMUTH: - case MaterialNames.LEAD: - case MaterialNames.PEWTER: - case MaterialNames.ZINC: + case MaterialNames.ANTIMONY : + case MaterialNames.BISMUTH : + case MaterialNames.LEAD : + case MaterialNames.PEWTER : + case MaterialNames.ZINC : return 1.0d; - case MaterialNames.ADAMANTINE: + case MaterialNames.ADAMANTINE : return 0.0d; - default: + default : return 1.0d; } } private static double getStrength(@Nonnull final String name) { switch (name) { - case MaterialNames.ADAMANTINE: + case MaterialNames.ADAMANTINE : return 100.0d; - case MaterialNames.STARSTEEL: + case MaterialNames.STARSTEEL : return 25.0d; - case MaterialNames.STEEL: + case MaterialNames.STEEL : return 15.0d; - case MaterialNames.INVAR: - case MaterialNames.AQUARIUM: + case MaterialNames.INVAR : + case MaterialNames.AQUARIUM : return 10.0d; - case MaterialNames.MITHRIL: + case MaterialNames.MITHRIL : return 9.0d; - case MaterialNames.COLDIRON: + case MaterialNames.COLDIRON : return 7.0d; - case MaterialNames.CUPRONICKEL: + case MaterialNames.CUPRONICKEL : return 6.0d; - case MaterialNames.PLATINUM: + case MaterialNames.PLATINUM : return 5.0d; - case MaterialNames.SILVER: - case MaterialNames.NICKEL: - case MaterialNames.ELECTRUM: - case MaterialNames.COPPER: - case MaterialNames.BRONZE: + case MaterialNames.SILVER : + case MaterialNames.NICKEL : + case MaterialNames.ELECTRUM : + case MaterialNames.COPPER : + case MaterialNames.BRONZE : return 4.0d; - case MaterialNames.BRASS: + case MaterialNames.BRASS : return 3.0d; - case MaterialNames.TIN: - case MaterialNames.ANTIMONY: - case MaterialNames.BISMUTH: - case MaterialNames.LEAD: - case MaterialNames.PEWTER: - case MaterialNames.ZINC: - default: + case MaterialNames.TIN : + case MaterialNames.ANTIMONY : + case MaterialNames.BISMUTH : + case MaterialNames.LEAD : + case MaterialNames.PEWTER : + case MaterialNames.ZINC : + default : return 1.0d; } } private static double getHardness(@Nonnull final String name) { switch (name) { - case MaterialNames.ADAMANTINE: + case MaterialNames.ADAMANTINE : return 12.0d; - case MaterialNames.STARSTEEL: + case MaterialNames.STARSTEEL : return 10.0d; - case MaterialNames.INVAR: - case MaterialNames.MITHRIL: + case MaterialNames.INVAR : + case MaterialNames.MITHRIL : return 9.0d; - case MaterialNames.STEEL: - case MaterialNames.BRONZE: + case MaterialNames.STEEL : + case MaterialNames.BRONZE : return 8.0d; - case MaterialNames.COLDIRON: + case MaterialNames.COLDIRON : return 7.0d; - case MaterialNames.CUPRONICKEL: + case MaterialNames.CUPRONICKEL : return 6.0d; - case MaterialNames.SILVER: - case MaterialNames.ELECTRUM: + case MaterialNames.SILVER : + case MaterialNames.ELECTRUM : return 5.0d; - case MaterialNames.COPPER: - case MaterialNames.AQUARIUM: - case MaterialNames.NICKEL: + case MaterialNames.COPPER : + case MaterialNames.AQUARIUM : + case MaterialNames.NICKEL : return 4.0d; - case MaterialNames.BRASS: + case MaterialNames.BRASS : return 3.5d; - case MaterialNames.TIN: - case MaterialNames.PLATINUM: + case MaterialNames.TIN : + case MaterialNames.PLATINUM : return 3.0d; - case MaterialNames.ANTIMONY: - case MaterialNames.BISMUTH: - case MaterialNames.LEAD: - case MaterialNames.PEWTER: - case MaterialNames.ZINC: - default: + case MaterialNames.ANTIMONY : + case MaterialNames.BISMUTH : + case MaterialNames.LEAD : + case MaterialNames.PEWTER : + case MaterialNames.ZINC : + default : return 1.0d; } } - } diff --git a/src/main/java/com/mcmoddev/basemetals/init/Recipes.java b/src/main/java/com/mcmoddev/basemetals/init/Recipes.java index 9dea21eb..3d20d910 100644 --- a/src/main/java/com/mcmoddev/basemetals/init/Recipes.java +++ b/src/main/java/com/mcmoddev/basemetals/init/Recipes.java @@ -18,14 +18,13 @@ import net.minecraftforge.oredict.OreDictionary; /** Registers Base Metals crafting, furnace, and crusher recipes. */ -@Mod.EventBusSubscriber(modid=BaseMetals.MODID) +@Mod.EventBusSubscriber(modid = BaseMetals.MODID) public final class Recipes extends com.mcmoddev.lib.init.Recipes { private Recipes() { throw new IllegalAccessError(SharedStrings.NOT_INSTANTIABLE); } - /** Registers the recipe handler on Forge's event bus. */ public static void init() { } @@ -35,6 +34,7 @@ private static void initModSpecificOredicts() { addAdditionalOredicts(adamantine, "Adamantite"); addAdditionalOredicts(adamantine, "Adamantium"); + if (!Loader.isModLoaded("taiga")) { addAdditionalOredicts(adamantine, "Adamant"); } @@ -56,7 +56,7 @@ private static void initModSpecificOredicts() { } /** Adds programmatic recipes and wraps restricted recipes with the content policy. */ - @SubscribeEvent(priority=EventPriority.LOWEST) + @SubscribeEvent(priority = EventPriority.LOWEST) public static void registerRecipes(final RegistryEvent.Register event) { initModSpecificOredicts(); register(event); diff --git a/src/main/java/com/mcmoddev/basemetals/init/VillagerTrades.java b/src/main/java/com/mcmoddev/basemetals/init/VillagerTrades.java index 8d3b9d23..1d712897 100644 --- a/src/main/java/com/mcmoddev/basemetals/init/VillagerTrades.java +++ b/src/main/java/com/mcmoddev/basemetals/init/VillagerTrades.java @@ -40,17 +40,20 @@ public static void init() { } else { registerRestrictedTrades(ContentPolicy.active()); } + registerModSpecificTrades(); } } private static void registerRestrictedTrades(final ContentPolicy policy) { final Map> enchanted = new HashMap<>(); + Materials.getMaterialsByMod(BaseMetals.MODID).stream() .filter(material -> !material.isEmpty() && !material.isRare()) .filter(VillagerTrades::hasAffordableTradeValue) .forEach(material -> { registerIngotTrades(material, policy); + if (material.getStat(MaterialStats.MAGICAFFINITY) > 5.0F) { registerEnchantedTrades(material, policy, enchanted); } @@ -60,6 +63,7 @@ private static void registerRestrictedTrades(final ContentPolicy policy) { private static boolean hasAffordableTradeValue(final MMDMaterial material) { final float value = tradeValue(material); + return emeraldPurchaseValue(value) < 65 && emeraldSaleValue(value) < 65; } @@ -76,14 +80,18 @@ private static void registerIngotTrades(final MMDMaterial material, || !policy.allows(material.getName(), MaterialForm.INGOT)) { return; } + final net.minecraft.item.ItemStack stack = material.getItemStack(Names.INGOT, 12); + if (stack.getItem() == net.minecraft.init.Items.EMERALD || stack.getItem() == net.minecraft.init.Items.DIAMOND) { return; } + final int price = emeraldPurchaseValue(tradeValue(material)); final int level = tradeLevel(tradeValue(material)); final ITradeList[] trades = makePurchasePalette(price, stack); + VillagerTradeHelper.insertTrades(SMITH_RL, ARMOR_SMITH_ID, level, trades); VillagerTradeHelper.insertTrades(SMITH_RL, WEAPON_SMITH_ID, level, trades); VillagerTradeHelper.insertTrades(SMITH_RL, TOOL_SMITH_ID, level, trades); @@ -93,6 +101,7 @@ private static void registerEnchantedTrades(final MMDMaterial material, final ContentPolicy policy, final Map> table) { final int level = tradeLevel(tradeValue(material)); final int basePrice = emeraldPurchaseValue(tradeValue(material)); + addEnchanted(table, WEAPON_SMITH | (level + 1), material, policy, basePrice, (int) (material.getBaseAttackDamage() / 2) - 1, Names.SWORD, Names.CROSSBOW, Names.BOW); @@ -113,6 +122,7 @@ private static void addEnchanted(final Map> table, || !policy.allows(material.getName(), toForm(name))) { continue; } + table.computeIfAbsent(key, ignored -> new ArrayList<>()) .addAll(Collections.singletonList(new ListEnchantedItemForEmeralds( material.getItem(name), new PriceInfo(basePrice + 7 + priceModifier, @@ -132,6 +142,7 @@ protected static void registerModSpecificTrades() { if (Materials.hasMaterial(MaterialNames.CHARCOAL)) { final MMDMaterial charcoal = Materials.getMaterialByName(MaterialNames.CHARCOAL); + if (charcoal.hasItem(Names.POWDER)) { final Item charcoalPowder = charcoal.getItem(Names.POWDER); final ITradeList[] charcoalTrades = makePurchasePalette(1, 10, charcoalPowder); @@ -144,6 +155,7 @@ protected static void registerModSpecificTrades() { if (Materials.hasMaterial(MaterialNames.COAL)) { final MMDMaterial coal = Materials.getMaterialByName(MaterialNames.COAL); + if (coal.hasItem(Names.POWDER)) { final Item coalPowder = coal.getItem(Names.POWDER); final ITradeList[] coalTrades = makePurchasePalette(1, 10, coalPowder); diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeConstructsArmory.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeConstructsArmory.java index 6b827d6e..ae66597f 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeConstructsArmory.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeConstructsArmory.java @@ -1,6 +1,5 @@ package com.mcmoddev.basemetals.integration.plugins; - import c4.conarm.common.armor.traits.ArmorTraits; import com.mcmoddev.basemetals.BaseMetals; import com.mcmoddev.basemetals.content.ContentMode; @@ -28,31 +27,33 @@ import static com.mcmoddev.lib.integration.plugins.ConstructsArmory.*; @MMDPlugin(addonId = BaseMetals.MODID, pluginId = BMeConstructsArmory.PLUGIN_MODID, versions = BMeConstructsArmory.PLUGIN_MODID - + "@[1.12.2-2.10.1.87,)") + + "@[1.12.2-2.10.1.87,)") public final class BMeConstructsArmory implements IIntegration { - public static final String PLUGIN_MODID = ConstructsArmory.PLUGIN_MODID; - private final List highFantasyMaterials = - new ArrayList<>(); + public static final String PLUGIN_MODID = ConstructsArmory.PLUGIN_MODID; + private final List highFantasyMaterials = new ArrayList<>(); - public BMeConstructsArmory() { - } + public BMeConstructsArmory() { + } - @Override - public void init() { - INSTANCE.init(); - if (!Config.Options.isModEnabled(PLUGIN_MODID)) { - return; - } - MinecraftForge.EVENT_BUS.register(this); - } + @Override + public void init() { + INSTANCE.init(); - @SubscribeEvent(priority = EventPriority.LOWEST) - public void materialRegistration(MaterialRegistrationEvent ev) { - if(Config.Options.isModEnabled(PLUGIN_MODID)){ + if (!Config.Options.isModEnabled(PLUGIN_MODID)) { + return; + } + + MinecraftForge.EVENT_BUS.register(this); + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void materialRegistration(MaterialRegistrationEvent ev) { + if (Config.Options.isModEnabled(PLUGIN_MODID)) { if (ContentPolicy.active().mode() != ContentMode.HIGH_FANTASY) { return; } + highFantasyMaterials.clear(); ev.getRegistry().getEntries().stream() .map(ent -> ent.getValue()) @@ -63,50 +64,53 @@ public void materialRegistration(MaterialRegistrationEvent ev) { /** Adds armor stats after ConArm has installed its default stat types. */ @SubscribeEvent(priority = EventPriority.HIGHEST) public void armorRegistration(final IntegrationInitEvent event) { - final Collection materials = - ContentPolicy.active().mode() == ContentMode.HIGH_FANTASY - ? highFantasyMaterials : BMeTinkersConstruct.restrictedMaterials(); + final Collection materials = ContentPolicy + .active().mode() == ContentMode.HIGH_FANTASY + ? highFantasyMaterials + : BMeTinkersConstruct.restrictedMaterials(); + materials.stream() .filter(mat -> ContentPolicy.active().allows(mat.getName(), MaterialForm.CHESTPLATE)) .forEach(mat -> { TinkerRegistry.addMaterialStats(mat.getTinkerMaterial(), mat.getCoreStats(), mat.getPlatesStats(), mat.getTrimStats()); - switch (mat.getName()){ - case MaterialNames.ADAMANTINE: - addArmorTrait(mat.getTinkerMaterial(), ArmorTraits.vengeful, ArmorTraits.prideful); - break; - case MaterialNames.ANTIMONY: - addArmorTrait(mat.getTinkerMaterial(), MMDTraitsCA.brittle); - break; - case MaterialNames.AQUARIUM: - addArmorTrait(mat.getTinkerMaterial(), ArmorTraits.rough, ArmorTraits.aquaspeed); - break; - case MaterialNames.BRASS: - addArmorTrait(mat.getTinkerMaterial(), ArmorTraits.dense); - break; - case MaterialNames.COLDIRON: - addArmorTrait(mat.getTinkerMaterial(), MMDTraitsCA.icy); - break; - case MaterialNames.LEAD: - // Keep the legacy trait request even though some ConArm versions ignore it. - addArmorTrait(mat.getTinkerMaterial(), MMDTraitsCA.malleable); - break; - case MaterialNames.MITHRIL: - addArmorTrait(mat.getTinkerMaterial(), ArmorTraits.blessed); - break; - case MaterialNames.NICKEL: - addArmorTrait(mat.getTinkerMaterial(), ArmorTraits.magnetic2, ArmorTraits.magnetic); - addArmorTrait(mat.getTinkerMaterial(), TinkerTraits.shocking); - break; - case MaterialNames.PEWTER: - addArmorTrait(mat.getTinkerMaterial(), MMDTraitsCA.malleable); - break; - case MaterialNames.STARSTEEL: - addArmorTrait(mat.getTinkerMaterial(), MMDTraits.sparkly, ArmorTraits.enderport); - break; - case MaterialNames.ZINC: - addArmorTrait(mat.getTinkerMaterial(), MMDTraitsCA.reactive); - } - }); + + switch (mat.getName()) { + case MaterialNames.ADAMANTINE : + addArmorTrait(mat.getTinkerMaterial(), ArmorTraits.vengeful, ArmorTraits.prideful); + break; + case MaterialNames.ANTIMONY : + addArmorTrait(mat.getTinkerMaterial(), MMDTraitsCA.brittle); + break; + case MaterialNames.AQUARIUM : + addArmorTrait(mat.getTinkerMaterial(), ArmorTraits.rough, ArmorTraits.aquaspeed); + break; + case MaterialNames.BRASS : + addArmorTrait(mat.getTinkerMaterial(), ArmorTraits.dense); + break; + case MaterialNames.COLDIRON : + addArmorTrait(mat.getTinkerMaterial(), MMDTraitsCA.icy); + break; + case MaterialNames.LEAD : + // Keep the legacy trait request even though some ConArm versions ignore it. + addArmorTrait(mat.getTinkerMaterial(), MMDTraitsCA.malleable); + break; + case MaterialNames.MITHRIL : + addArmorTrait(mat.getTinkerMaterial(), ArmorTraits.blessed); + break; + case MaterialNames.NICKEL : + addArmorTrait(mat.getTinkerMaterial(), ArmorTraits.magnetic2, ArmorTraits.magnetic); + addArmorTrait(mat.getTinkerMaterial(), TinkerTraits.shocking); + break; + case MaterialNames.PEWTER : + addArmorTrait(mat.getTinkerMaterial(), MMDTraitsCA.malleable); + break; + case MaterialNames.STARSTEEL : + addArmorTrait(mat.getTinkerMaterial(), MMDTraits.sparkly, ArmorTraits.enderport); + break; + case MaterialNames.ZINC : + addArmorTrait(mat.getTinkerMaterial(), MMDTraitsCA.reactive); + } + }); } } diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeDenseOres.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeDenseOres.java index 415f20a4..dc7d3029 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeDenseOres.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeDenseOres.java @@ -26,7 +26,7 @@ public void init() { registerOres(); } - /** Registers every policy-permitted Base Metals ore with Dense Ores. */ + /** Adds Dense Ores variants for ores allowed by the content mode. */ private static void registerOres() { final List materials = Arrays.asList(MaterialNames.ADAMANTINE, MaterialNames.ANTIMONY, MaterialNames.BISMUTH, MaterialNames.COLDIRON, @@ -39,14 +39,16 @@ private static void registerOres() { .filter(materialName -> ContentPolicy.active().allows(materialName, MaterialForm.ORE)) .forEach(materialName -> { String baseMaterial; + switch (materialName) { - case MaterialNames.ADAMANTINE: - case MaterialNames.COLDIRON: + case MaterialNames.ADAMANTINE : + case MaterialNames.COLDIRON : baseMaterial = Oredicts.NETHERRACK; break; - default: + default : baseMaterial = Oredicts.STONE; } + registerOre(String.format("%s_%s", materialName, Oredicts.ORE), baseMaterial, 0); }); diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeEnderIO.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeEnderIO.java index 46bf6ac3..bbd8f92a 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeEnderIO.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeEnderIO.java @@ -55,41 +55,45 @@ public void init() { final String ZINC = "Zinc"; final List>> alloys = Arrays.asList( Pair.of(3, Triple.of(MaterialNames.AQUARIUM, 20000, - new Object[] { Oredicts.INGOT + COPPER, 2, Oredicts.INGOT + ZINC, 1, Oredicts.DUST + "Prismarine", 1 })), + new Object[]{Oredicts.INGOT + COPPER, 2, Oredicts.INGOT + ZINC, 1, Oredicts.DUST + "Prismarine", + 1})), Pair.of(3, Triple.of(MaterialNames.BRASS, 2000, - new Object[] { Oredicts.INGOT + COPPER, 2, Oredicts.INGOT + ZINC, 1 })), + new Object[]{Oredicts.INGOT + COPPER, 2, Oredicts.INGOT + ZINC, 1})), Pair.of(4, Triple.of(MaterialNames.BRONZE, 2000, - new Object[] { Oredicts.INGOT + COPPER, 3, Oredicts.INGOT + TIN, 1 })), + new Object[]{Oredicts.INGOT + COPPER, 3, Oredicts.INGOT + TIN, 1})), Pair.of(4, Triple.of(MaterialNames.CUPRONICKEL, 3000, - new Object[] { Oredicts.INGOT + COPPER, 3, Oredicts.INGOT + NICKEL, 1})), + new Object[]{Oredicts.INGOT + COPPER, 3, Oredicts.INGOT + NICKEL, 1})), Pair.of(3, Triple.of(MaterialNames.INVAR, 3000, - new Object[] { Oredicts.INGOT + IRON, 2, Oredicts.INGOT + NICKEL, 1})), + new Object[]{Oredicts.INGOT + IRON, 2, Oredicts.INGOT + NICKEL, 1})), Pair.of(2, Triple.of(MaterialNames.ELECTRUM, 2000, - new Object[] { Oredicts.INGOT + "Gold", 1, Oredicts.INGOT + SILVER, 1 })), + new Object[]{Oredicts.INGOT + "Gold", 1, Oredicts.INGOT + SILVER, 1})), Pair.of(2, Triple.of(MaterialNames.MITHRIL, 10000, - new Object[] { Oredicts.INGOT + SILVER, 2, Oredicts.INGOT + "Coldiron", 1, Oredicts.INGOT + "Mercury", 1 })), + new Object[]{Oredicts.INGOT + SILVER, 2, Oredicts.INGOT + "Coldiron", 1, + Oredicts.INGOT + "Mercury", 1})), Pair.of(3, Triple.of(MaterialNames.PEWTER, 2000, - new Object[] { Oredicts.INGOT + TIN, 1, Oredicts.INGOT + COPPER, 1, Oredicts.INGOT + "Lead", 1 })), + new Object[]{Oredicts.INGOT + TIN, 1, Oredicts.INGOT + COPPER, 1, Oredicts.INGOT + "Lead", 1})), Pair.of(8, Triple.of(MaterialNames.STEEL, 5000, - new Object[] { Oredicts.INGOT + IRON, 8, "itemCoal", 1 }))); + new Object[]{Oredicts.INGOT + IRON, 8, "itemCoal", 1}))); + alloys.stream() - .filter(p -> Materials.hasMaterial(p.getRight().getLeft())) - .filter(p -> ContentPolicy.active().allows(p.getRight().getLeft(), MaterialForm.INGOT)) - .forEach(p -> { - final String name = p.getRight().getLeft(); - final int count = p.getLeft(); - final int cost = p.getRight().getMiddle(); - final Object[] recipe = p.getRight().getRight(); + .filter(p -> Materials.hasMaterial(p.getRight().getLeft())) + .filter(p -> ContentPolicy.active().allows(p.getRight().getLeft(), MaterialForm.INGOT)) + .forEach(p -> { + final String name = p.getRight().getLeft(); + final int count = p.getLeft(); + final int cost = p.getRight().getMiddle(); + final Object[] recipe = p.getRight().getRight(); - final MMDMaterial material = Materials.getMaterialByName(name); - addAlloySmelterAlloy(material, cost, Oredicts.INGOT + material.getCapitalizedName(), count, recipe); - }); + final MMDMaterial material = Materials.getMaterialByName(name); + addAlloySmelterAlloy(material, cost, Oredicts.INGOT + material.getCapitalizedName(), count, recipe); + }); } private static void addSagMillRecipeIfAllowed(final String primary, final int primaryCount, final String secondary, final int secondaryCount, final int energy) { final ContentPolicy policy = ContentPolicy.active(); + if (policy.allows(primary, MaterialForm.POWDER) && policy.allows(secondary, MaterialForm.POWDER)) { addSagMillRecipe(primary, primaryCount, secondary, secondaryCount, energy); diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeIC2.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeIC2.java index 9a80d53a..5ad5b420 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeIC2.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeIC2.java @@ -4,7 +4,6 @@ import java.util.List; import com.mcmoddev.basemetals.BaseMetals; -import com.mcmoddev.basemetals.content.ContentPolicy; import com.mcmoddev.basemetals.data.MaterialNames; import com.mcmoddev.lib.data.Names; import com.mcmoddev.lib.init.Materials; @@ -21,7 +20,8 @@ import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -@MMDPlugin(addonId = BaseMetals.MODID, pluginId = BMeIC2.PLUGIN_MODID, versions = BMeIC2.PLUGIN_MODID + "@[2.8.57-ex112,)") +@MMDPlugin(addonId = BaseMetals.MODID, pluginId = BMeIC2.PLUGIN_MODID, versions = BMeIC2.PLUGIN_MODID + + "@[2.8.57-ex112,)") public final class BMeIC2 extends IC2 implements IIntegration { private static final List materials = Arrays.asList(MaterialNames.ADAMANTINE, @@ -44,7 +44,6 @@ public void mainInteraction(final RegistryEvent.Register event) { materials.stream().filter(Materials::hasMaterial) .filter(materialName -> !Materials.getMaterialByName(materialName).isEmpty()) - .filter(ContentPolicy.active()::allowsMaterial) .forEach(materialName -> { this.registerVanillaRecipes(materialName); this.addMaceratorRecipes(materialName); @@ -57,6 +56,7 @@ public void mainInteraction(final RegistryEvent.Register event) { if (Materials.hasMaterial(MaterialNames.DIAMOND)) { final MMDMaterial diamond = Materials.getMaterialByName(MaterialNames.DIAMOND); final String oreDictName = diamond.getCapitalizedName(); + if (diamond.hasItem(Names.POWDER)) { this.addMaceratorRecipe(Oredicts.ORE + oreDictName, diamond.getItemStack(Names.POWDER, 2)); @@ -66,6 +66,7 @@ public void mainInteraction(final RegistryEvent.Register event) { if (Materials.hasMaterial(MaterialNames.EMERALD)) { final MMDMaterial emerald = Materials.getMaterialByName(MaterialNames.EMERALD); final String oreDictName = emerald.getCapitalizedName(); + if (emerald.hasItem(Names.POWDER)) { this.addMaceratorRecipe(Oredicts.ORE + oreDictName, emerald.getItemStack(Names.POWDER, 2)); @@ -80,7 +81,6 @@ public void mainInteraction(final RegistryEvent.Register event) { public void doHammerRecipes(final IntegrationInitEvent event) { materials.stream().filter(Materials::hasMaterial) .filter(materialName -> !Materials.getMaterialByName(materialName).isEmpty()) - .filter(ContentPolicy.active()::allowsMaterial) .forEach(this::addForgeHammerRecipe); } } diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeMekanism.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeMekanism.java index 2be8b7e1..756ace4f 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeMekanism.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeMekanism.java @@ -6,7 +6,6 @@ import javax.annotation.Nonnull; import com.mcmoddev.basemetals.BaseMetals; -import com.mcmoddev.basemetals.content.ContentPolicy; import com.mcmoddev.basemetals.data.MaterialNames; import com.mcmoddev.lib.data.Names; import com.mcmoddev.lib.init.Materials; @@ -38,7 +37,6 @@ public void init() { MinecraftForge.EVENT_BUS.register(this); materials.stream().filter(Materials::hasMaterial).filter(BMeMekanism::isMaterialNotEmpty) - .filter(ContentPolicy.active()::allowsMaterial) .forEach(Mekanism::addGassesForMaterial); } @@ -51,12 +49,12 @@ private static boolean isMaterialNotEmpty(@Nonnull final String materialName) { public void regCallback(final RegistryEvent.Register event) { materials.stream().filter(Materials::hasMaterial).filter(BMeMekanism::isMaterialNotEmpty) - .filter(ContentPolicy.active()::allowsMaterial) .forEach(Mekanism::addOreMultiplicationRecipes); if (Materials.hasMaterial(MaterialNames.DIAMOND)) { this.addVanillaOreMultiplicationRecipes(MaterialNames.DIAMOND); } + if (Materials.hasMaterial(MaterialNames.EMERALD)) { this.addVanillaOreMultiplicationRecipes(MaterialNames.EMERALD); } @@ -70,10 +68,12 @@ private void addVanillaOreMultiplicationRecipes(final String materialName) { addCrusherRecipe(material.getBlockItemStack(Names.ORE), material.getItemStack(Names.INGOT, 2)); } + if (material.hasItem(Names.INGOT) && (material.hasItem(Names.POWDER))) { addCrusherRecipe(material.getItemStack(Names.INGOT), material.getItemStack(Names.POWDER)); } + if (material.hasBlock(Names.ORE) && (material.hasItem(Names.POWDER))) { addPurificationChamberRecipe(material.getBlockItemStack(Names.ORE), material.getItemStack(Names.POWDER, 2)); diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeThaumcraft.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeThaumcraft.java index 67f171e5..3b0618fb 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeThaumcraft.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeThaumcraft.java @@ -25,88 +25,95 @@ @MMDPlugin(addonId = BaseMetals.MODID, pluginId = BMeThaumcraft.PLUGIN_MODID, versions = BMeThaumcraft.PLUGIN_MODID + "@[1.12-6.1.BETA,)") -public final class BMeThaumcraft implements IIntegration { +public final class BMeThaumcraft implements IIntegration { public static final String PLUGIN_MODID = Thaumcraft.PLUGIN_MODID; private static final Map tcMaterials = new HashMap<>(); - public BMeThaumcraft() { if (!Config.Options.isModEnabled(PLUGIN_MODID)) { return; } - + MinecraftForge.EVENT_BUS.register(this.getClass()); } - + @Override public void init() { if (!Config.Options.isModEnabled(PLUGIN_MODID)) { return; } + Thaumcraft.INSTANCE.init(); } - + @SubscribeEvent public static void preInit(IntegrationPreInitEvent ev) { - List materials = Arrays.asList(MaterialNames.COPPER, MaterialNames.SILVER, MaterialNames.DIAMOND, - MaterialNames.EMERALD, MaterialNames.STEEL, MaterialNames.BRASS, MaterialNames.BRONZE, MaterialNames.TIN, + List materials = Arrays.asList(MaterialNames.COPPER, MaterialNames.SILVER, MaterialNames.DIAMOND, + MaterialNames.EMERALD, MaterialNames.STEEL, MaterialNames.BRASS, MaterialNames.BRONZE, + MaterialNames.TIN, MaterialNames.MITHRIL, MaterialNames.AQUARIUM); - + Materials.getAllMaterials().stream() - .filter(mat -> !mat.isVanilla()) - .filter(mat -> !mat.isEmpty()) - .forEach(mat -> { - String mn = mat.getName(); - TCMaterial tcm = Thaumcraft.createWithAspects(mat); - tcMaterials.put(mn, tcm); - }); + .filter(mat -> !mat.isVanilla()) + .filter(mat -> !mat.isEmpty()) + .forEach(mat -> { + String mn = mat.getName(); + TCMaterial tcm = Thaumcraft.createWithAspects(mat); + + tcMaterials.put(mn, tcm); + }); Materials.getAllMaterials().stream() - .filter( mat -> mat.isVanilla()) - .filter( mat -> !mat.isEmpty()) - .filter( mat -> mat.getType() == MMDMaterialType.MaterialType.MINERAL - || mat.getType() == MMDMaterialType.MaterialType.ROCK) - .forEach( mat -> { - String mn = mat.getName(); - TCMaterial tcm = Thaumcraft.createVanillaIngotWithAspects(mat); - tcMaterials.put(mn, tcm); - }); - + .filter(mat -> mat.isVanilla()) + .filter(mat -> !mat.isEmpty()) + .filter(mat -> mat.getType() == MMDMaterialType.MaterialType.MINERAL + || mat.getType() == MMDMaterialType.MaterialType.ROCK) + .forEach(mat -> { + String mn = mat.getName(); + TCMaterial tcm = Thaumcraft.createVanillaIngotWithAspects(mat); + + tcMaterials.put(mn, tcm); + }); + materials.stream() - .filter(Materials::hasMaterial) - .forEach(BMeThaumcraft::makeSpecialMaterial); - + .filter(Materials::hasMaterial) + .forEach(BMeThaumcraft::makeSpecialMaterial); + tcMaterials.entrySet().stream().map(ent -> ent.getValue()).forEach(tc -> tc.update()); } - + private static void makeSpecialMaterial(String name) { - TCMaterial thisMat = tcMaterials.getOrDefault(name, Thaumcraft.createWithAspects(Materials.getMaterialByName(name))); - switch(name) { - case "mithril": - case "aquarium": - thisMat.addMaterialAspect(Aspect.MAGIC, 5); - break; - case "copper": - thisMat.addMaterialAspect(Aspect.EXCHANGE, 5); - break; - case "tin": - thisMat.addMaterialAspect(Aspect.CRYSTAL, 5); - break; - case "steel": - thisMat.addMaterialAspect(Aspect.ORDER, 5); - break; - case "brass": - case "bronze": - thisMat.addMaterialAspect(Aspect.TOOL, 5); - break; - case "silver": - case "diamond": - case "emerald": - MMDMaterial mat = thisMat.getMMDMaterial(); - thisMat.addMaterialAspect(Aspect.DESIRE, (m) -> mat.isRare()?(int)(mat.getStat(MaterialStats.MAGICAFFINITY) * 2/ 45 * m):5); - break; + TCMaterial thisMat = tcMaterials.getOrDefault(name, + Thaumcraft.createWithAspects(Materials.getMaterialByName(name))); + + switch (name) { + case "mithril" : + case "aquarium" : + thisMat.addMaterialAspect(Aspect.MAGIC, 5); + break; + case "copper" : + thisMat.addMaterialAspect(Aspect.EXCHANGE, 5); + break; + case "tin" : + thisMat.addMaterialAspect(Aspect.CRYSTAL, 5); + break; + case "steel" : + thisMat.addMaterialAspect(Aspect.ORDER, 5); + break; + case "brass" : + case "bronze" : + thisMat.addMaterialAspect(Aspect.TOOL, 5); + break; + case "silver" : + case "diamond" : + case "emerald" : + MMDMaterial mat = thisMat.getMMDMaterial(); + thisMat.addMaterialAspect(Aspect.DESIRE, + (m) -> mat.isRare() ? (int) (mat.getStat(MaterialStats.MAGICAFFINITY) * 2 / 45 * m) : 5); + break; } + tcMaterials.put(name, thisMat); } diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeThermalExpansion.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeThermalExpansion.java index f80c5485..587a9aba 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeThermalExpansion.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeThermalExpansion.java @@ -21,8 +21,8 @@ import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -@MMDPlugin(addonId = BaseMetals.MODID, pluginId = BMeThermalExpansion.PLUGIN_MODID, - versions = BMeThermalExpansion.PLUGIN_MODID + "@(,5.3.12.17];") +@MMDPlugin(addonId = BaseMetals.MODID, pluginId = BMeThermalExpansion.PLUGIN_MODID, versions = BMeThermalExpansion.PLUGIN_MODID + + "@(,5.3.12.17];") public final class BMeThermalExpansion extends ThermalExpansion implements IIntegration { @Override @@ -47,11 +47,26 @@ public void regShit(final RegistryEvent.Register event) { .filter(materialName -> !Materials.getMaterialByName(materialName).isEmpty()) .forEach(materialName -> { final ContentPolicy policy = ContentPolicy.active(); - if (policy.allows(materialName, MaterialForm.INGOT)) addFurnace(materialName); - if (policy.allows(materialName, MaterialForm.FLUID)) addCrucible(materialName); - if (policy.allows(materialName, MaterialForm.PLATE)) addPlatePress(materialName); - if (policy.allows(materialName, MaterialForm.BLOCK)) addPressStorage(materialName); - if (policy.allows(materialName, MaterialForm.POWDER)) addPulverizer(materialName); + + if (policy.allows(materialName, MaterialForm.INGOT)) { + addFurnace(materialName); + } + + if (policy.allows(materialName, MaterialForm.FLUID)) { + addCrucible(materialName); + } + + if (policy.allows(materialName, MaterialForm.PLATE)) { + addPlatePress(materialName); + } + + if (policy.allows(materialName, MaterialForm.BLOCK)) { + addPressStorage(materialName); + } + + if (policy.allows(materialName, MaterialForm.POWDER)) { + addPulverizer(materialName); + } }); final MMDMaterial brass = Materials.getMaterialByName(MaterialNames.BRASS); @@ -97,6 +112,7 @@ private static boolean materialsHaveItems(final List materialNames, } } } + return true; } @@ -106,6 +122,7 @@ private static boolean hasMaterials(final String... materials) { return false; } } + return true; } } diff --git a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeTinkersConstruct.java b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeTinkersConstruct.java index 6056514c..2b6a5271 100644 --- a/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeTinkersConstruct.java +++ b/src/main/java/com/mcmoddev/basemetals/integration/plugins/BMeTinkersConstruct.java @@ -59,8 +59,7 @@ public class BMeTinkersConstruct implements IIntegration { public static final String PLUGIN_MODID = TinkersConstruct.PLUGIN_MODID; - private static final Map RESTRICTED_MATERIALS = - new LinkedHashMap<>(); + private static final Map RESTRICTED_MATERIALS = new LinkedHashMap<>(); public BMeTinkersConstruct() { } @@ -68,61 +67,67 @@ public BMeTinkersConstruct() { @Override public void init() { TinkersConstruct.INSTANCE.init(); - if(!slimeknights.tconstruct.TConstruct.pulseManager.isPulseLoaded("TinkerSmeltery")) { - return; - } - if (!Options.isModEnabled(PLUGIN_MODID)) { + + if (!slimeknights.tconstruct.TConstruct.pulseManager.isPulseLoaded("TinkerSmeltery")) { + return; + } + + if (!Options.isModEnabled(PLUGIN_MODID)) { return; } + MinecraftForge.EVENT_BUS.register(this); } - @SubscribeEvent(priority=EventPriority.LOWEST) + @SubscribeEvent(priority = EventPriority.LOWEST) public void registerMiscShit(RegistryEvent.Register ev) { - List items = Arrays.asList( Names.CHESTPLATE, Names.LEGGINGS, Names.HELMET, Names.BOOTS); - List materials = (List)Materials.getMaterialsByMod(BaseMetals.MODID); + List items = Arrays.asList(Names.CHESTPLATE, Names.LEGGINGS, Names.HELMET, Names.BOOTS); + List materials = (List) Materials.getMaterialsByMod(BaseMetals.MODID); + materials.stream() - .filter( b -> b.getFluid() != null) - .forEach( base -> - items.stream() - .filter(n -> ContentPolicy.active().allows(base.getName(), - MaterialForm.fromRegistryPath(base.getName() + "_" + n.toString()))) - .filter( n -> base.hasItem(n)) - .filter( nv -> base.getItem(nv).getRegistryName().getNamespace().equalsIgnoreCase(BaseMetals.MODID)) - .map( name -> Pair.of(name.toString(), Integer.valueOf(CheeseMath.getIngotCount(base, base.getItemStack(name))))) - .filter( evx -> evx.getValue() > 1) - .forEach( evga -> TinkersConstruct.INSTANCE.addExtraMelting(base.getName(), evga.getRight() * Material.VALUE_Ingot, base.getItemStack(evga.getLeft())))); + .filter(b -> b.getFluid() != null) + .forEach(base -> items.stream() + .filter(n -> ContentPolicy.active().allows(base.getName(), + MaterialForm.fromRegistryPath(base.getName() + "_" + n.toString()))) + .filter(n -> base.hasItem(n)) + .filter(nv -> base.getItem(nv).getRegistryName().getNamespace() + .equalsIgnoreCase(BaseMetals.MODID)) + .map(name -> Pair.of(name.toString(), + Integer.valueOf(CheeseMath.getIngotCount(base, base.getItemStack(name))))) + .filter(evx -> evx.getValue() > 1) + .forEach(evga -> TinkersConstruct.INSTANCE.addExtraMelting(base.getName(), + evga.getRight() * Material.VALUE_Ingot, base.getItemStack(evga.getLeft())))); } @SubscribeEvent - public void postInit(final IntegrationPostInitEvent event){ + public void postInit(final IntegrationPostInitEvent event) { if (Options.isFluidEnabled(MaterialNames.PRISMARINE) && isMaterialFluidEnabled(MaterialNames.PRISMARINE)) { registerPrismarineFullCasting(); } - // Ender casting follows the existing per-fluid switch, like prismarine above. + if (Options.isFluidEnabled(MaterialNames.ENDER) && isMaterialFluidEnabled(MaterialNames.ENDER)) { registerEnderFullCasting(); } } - private static void registerPrismarineFullCasting(){ + private static void registerPrismarineFullCasting() { int gemAmount = 144; int blockAmount = 4 * gemAmount; Fluid fluid = FluidRegistry.getFluid(MaterialNames.PRISMARINE); - registerTableCasting(new ItemStack(Items.PRISMARINE_SHARD, 1), TinkerSmeltery.castGem, fluid, gemAmount); - registerBasinCasting(new ItemStack(Blocks.PRISMARINE, 1),fluid, blockAmount); + registerTableCasting(new ItemStack(Items.PRISMARINE_SHARD, 1), TinkerSmeltery.castGem, fluid, gemAmount); + registerBasinCasting(new ItemStack(Blocks.PRISMARINE, 1), fluid, blockAmount); } - private static void registerEnderFullCasting(){ + private static void registerEnderFullCasting() { int gemAmount = 144; Fluid fluid = FluidRegistry.getFluid(MaterialNames.ENDER); - registerTableCasting(new ItemStack(Items.ENDER_PEARL, 1), TinkerSmeltery.castGem, fluid, gemAmount); + registerTableCasting(new ItemStack(Items.ENDER_PEARL, 1), TinkerSmeltery.castGem, fluid, gemAmount); } @SubscribeEvent @@ -166,15 +171,15 @@ public void materialRegistration(MaterialRegistrationEvent ev) { } /** - * MMDLib's material wrapper unconditionally adds bow, bowstring, shaft and - * fletching statistics. Restricted modes therefore integrate their materials - * directly after MMDLib has finished, adding only policy-permitted stat families. + * Register Low Fantasy materials ourselves: MMDLib always adds ranged stats, + * including bows. Wait for its registration to finish before adding our parts. */ @SubscribeEvent(priority = EventPriority.LOW) public void restrictedMaterialRegistration(final IntegrationPreInitEvent event) { if (ContentPolicy.active().mode() == ContentMode.HIGH_FANTASY) { return; } + RESTRICTED_MATERIALS.clear(); registerRestrictedMaterial(MaterialNames.ADAMANTINE, TraitNames.COLDBLOODED, TraitNames.INSATIABLE); @@ -203,56 +208,72 @@ public void restrictedMaterialRegistration(final IntegrationPreInitEvent event) private static void registerRestrictedMaterial(final String name, final Object... traits) { final ContentPolicy policy = ContentPolicy.active(); - if (!Options.isMaterialEnabled(name) || !Materials.hasMaterial(name) - || !policy.allowsMaterial(name)) { + + if (!Options.isMaterialEnabled(name) || !Materials.hasMaterial(name)) { return; } + final MMDMaterial base = Materials.getMaterialByName(name); + if (base.isEmpty()) { return; } + final TinkersMaterial helper = new TinkersMaterial(base) .setCastable(true).setCraftable(false).setToolForge(true).create(); final Material material = helper.getTinkerMaterial(); final boolean toolParts = policy.allows(name, MaterialForm.PICKAXE); final boolean ammunition = policy.allows(name, MaterialForm.ARROW); + if (toolParts) { TinkerRegistry.addMaterialStats(material, helper.getHeadStats(), helper.getHandleStats(), helper.getExtraStats()); } + if (ammunition) { TinkerRegistry.addMaterialStats(material, helper.getArrowShaftStats(), helper.getFletchingStats()); } + material.setCastable(true).setCraftable(false); material.addCommonItems(base.getCapitalizedName()); + if (base.hasItem(Names.INGOT)) { material.setRepresentativeItem(base.getItemStack(Names.INGOT)); } + material.setVisible(); material.setFluid(base.getFluid()); addRestrictedTraits(material, traits); + final MaterialIntegration integration = TinkerRegistry.integrate(material, base.getFluid(), base.getCapitalizedName()); + if (toolParts) { integration.toolforge(); } + if (TinkerRegistry.getMaterial(material.getIdentifier()) == Material.UNKNOWN) { TinkerRegistry.addMaterial(material); } + RESTRICTED_MATERIALS.put(name, helper); } private static void addRestrictedTraits(final Material material, final Object... traits) { int index = 0; + while (index < traits.length) { TinkerTraitLocation location = TinkerTraitLocation.GENERAL; Object entry = traits[index++]; + if (entry instanceof TinkerTraitLocation) { location = (TinkerTraitLocation) entry; entry = traits[index++]; } + final ITrait trait = TinkerRegistry.getTrait(((String) entry).toLowerCase(Locale.US)); + if (trait != null) { if (location == TinkerTraitLocation.GENERAL) { material.addTrait(trait); @@ -267,16 +288,17 @@ static Collection restrictedMaterials() { return Collections.unmodifiableCollection(RESTRICTED_MATERIALS.values()); } - protected void registerMaterial(final String name, MaterialRegistrationEvent ev, final Object... traits){ + protected void registerMaterial(final String name, MaterialRegistrationEvent ev, final Object... traits) { registerMaterial(Options.isMaterialEnabled(name), name, ev, traits); } protected void registerMaterial(final boolean active, final String name, - MaterialRegistrationEvent ev, final Object... traits) { + MaterialRegistrationEvent ev, final Object... traits) { registerMaterial(active, name, true, false, ev, traits); } - protected void registerMaterial(final boolean active, final String name, final boolean castable, final boolean craftable, + protected void registerMaterial(final boolean active, final String name, final boolean castable, + final boolean craftable, MaterialRegistrationEvent ev, final Object... traits) { if (active) { TinkersMaterial mat = new TinkersMaterial(Materials.getMaterialByName(name)) @@ -284,21 +306,24 @@ protected void registerMaterial(final boolean active, final String name, final b int i = 0; - while(i < traits.length) { + while (i < traits.length) { TinkerTraitLocation loc; String trait; Object item = traits[i]; - if(item instanceof TinkerTraitLocation) { - loc = (TinkerTraitLocation)item; - trait = ((String)traits[++i]).toLowerCase(Locale.US); + + if (item instanceof TinkerTraitLocation) { + loc = (TinkerTraitLocation) item; + trait = ((String) traits[++i]).toLowerCase(Locale.US); mat.addTrait(trait, loc); } else { - trait = ((String)item).toLowerCase(Locale.US); + trait = ((String) item).toLowerCase(Locale.US); mat.addTrait(trait); } + i++; } + ev.getRegistry().register(mat.create()); } } @@ -312,29 +337,32 @@ public void registerMeltings(TinkersExtraMeltingsEvent ev) { if (isMaterialFluidEnabled(MaterialNames.ENDER)) { final MMDMaterial ender = Materials.getMaterialByName(MaterialNames.ENDER); + TinkersConstruct.INSTANCE.addExtraMelting(FluidRegistry.getFluidStack(ender.getName(), 144), - new ItemStack(Items.ENDER_PEARL)); + new ItemStack(Items.ENDER_PEARL)); } if (isMaterialFluidEnabled(MaterialNames.MERCURY) && ContentPolicy.active().allows(MaterialNames.MERCURY, MaterialForm.INGOT)) { final MMDMaterial mercury = Materials.getMaterialByName(MaterialNames.MERCURY); + TinkersConstruct.INSTANCE.addExtraMelting(FluidRegistry.getFluidStack(mercury.getName(), 144), mercury.getItemStack(Names.INGOT)); } if (isMaterialFluidEnabled(MaterialNames.PRISMARINE)) { final MMDMaterial prismarine = Materials.getMaterialByName(MaterialNames.PRISMARINE); + TinkersConstruct.INSTANCE.addExtraMelting(FluidRegistry.getFluidStack(prismarine.getName(), 144), new ItemStack(net.minecraft.init.Items.PRISMARINE_SHARD)); } } - private boolean isMaterialFluidEnabled(String identifier){ + private boolean isMaterialFluidEnabled(String identifier) { return Options.isMaterialEnabled(identifier) && FluidRegistry.getFluid(identifier) != null; } - private boolean isValidAlloyMaterial(String identifier){ + private boolean isValidAlloyMaterial(String identifier) { return Materials.hasMaterial(identifier) && FluidRegistry.getFluid(identifier) != null && ContentPolicy.active().allows(identifier, MaterialForm.FLUID); } @@ -348,6 +376,7 @@ && isValidAlloyMaterial(MaterialNames.PRISMARINE)) { final FluidStack copper = FluidRegistry.getFluidStack(MaterialNames.COPPER, 2); final FluidStack zinc = FluidRegistry.getFluidStack(MaterialNames.ZINC, 1); final FluidStack prismarine = FluidRegistry.getFluidStack(MaterialNames.PRISMARINE, 3); + ev.addAlloyRecipe(MaterialNames.AQUARIUM, 3, copper, zinc, prismarine); } @@ -356,6 +385,7 @@ && isValidAlloyMaterial(MaterialNames.COPPER) && isValidAlloyMaterial(MaterialNames.NICKEL)) { final FluidStack copper = FluidRegistry.getFluidStack(MaterialNames.COPPER, 3); final FluidStack nickel = FluidRegistry.getFluidStack(MaterialNames.NICKEL, 1); + ev.addAlloyRecipe(MaterialNames.CUPRONICKEL, 4, copper, nickel); } @@ -363,6 +393,7 @@ && isValidAlloyMaterial(MaterialNames.NICKEL)) { && isValidAlloyMaterial(MaterialNames.NICKEL)) { final FluidStack iron = FluidRegistry.getFluidStack(MaterialNames.IRON, 2); final FluidStack nickel = FluidRegistry.getFluidStack(MaterialNames.NICKEL, 1); + ev.addAlloyRecipe(MaterialNames.INVAR, 3, iron, nickel); } @@ -373,6 +404,7 @@ && isValidAlloyMaterial(MaterialNames.MERCURY)) { final FluidStack coldiron = FluidRegistry.getFluidStack(MaterialNames.COLDIRON, 1); final FluidStack silver = FluidRegistry.getFluidStack(MaterialNames.SILVER, 2); final FluidStack mercury = FluidRegistry.getFluidStack(MaterialNames.MERCURY, 1); + ev.addAlloyRecipe(MaterialNames.MITHRIL, 3, coldiron, silver, mercury); } @@ -383,12 +415,14 @@ && isValidAlloyMaterial(MaterialNames.TIN)) { final FluidStack copper = FluidRegistry.getFluidStack(MaterialNames.COPPER, 2); final FluidStack tin = FluidRegistry.getFluidStack(MaterialNames.TIN, 137); final FluidStack lead = FluidRegistry.getFluidStack(MaterialNames.LEAD, 5); + ev.addAlloyRecipe(MaterialNames.PEWTER, 144, copper, tin, lead); } if (isValidAlloyMaterial(MaterialNames.STEEL)) { final FluidStack iron = FluidRegistry.getFluidStack(MaterialNames.IRON, 8); final FluidStack coal = FluidRegistry.getFluidStack(MaterialNames.COAL, 1); + ev.addAlloyRecipe(MaterialNames.STEEL, 8, iron, coal); } } diff --git a/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsArrow.java b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsArrow.java index d78b490a..5eaeeccf 100644 --- a/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsArrow.java +++ b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsArrow.java @@ -21,10 +21,14 @@ public ItemBaseMetalsArrow(final MMDMaterial material) { public EntityCustomArrow createArrow(final World world, final ItemStack ammunition, final EntityPlayer shooter) { final ItemStack projectileAmmunition = ammunition.copy(); + projectileAmmunition.setCount(1); + final EntityCustomArrow projectile = super.createArrow( world, projectileAmmunition, shooter); + MaterialRangedDamage.applyComponent(projectile, getMMDMaterial()); + return projectile; } @@ -34,8 +38,11 @@ public EntityArrow createArrow(final World world, final ItemStack ammunition, if (shooter instanceof EntityPlayer) { return createArrow(world, ammunition, (EntityPlayer) shooter); } + final EntityArrow projectile = super.createArrow(world, ammunition, shooter); + MaterialRangedDamage.applyComponent(projectile, getMMDMaterial()); + return projectile; } } diff --git a/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBolt.java b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBolt.java index 512422c8..51785a43 100644 --- a/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBolt.java +++ b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBolt.java @@ -19,7 +19,9 @@ public ItemBaseMetalsBolt(final MMDMaterial material) { public EntityCustomBolt createBolt(final World world, final ItemStack ammunition, final EntityPlayer shooter) { final EntityCustomBolt projectile = super.createBolt(world, ammunition, shooter); + MaterialRangedDamage.applyComponent(projectile, getMMDMaterial()); + return projectile; } } diff --git a/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBow.java b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBow.java index 9350c1fc..d2c15a42 100644 --- a/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBow.java +++ b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsBow.java @@ -39,8 +39,10 @@ public void onPlayerStoppedUsing(final ItemStack bow, final World world, || EnchantmentHelper.getEnchantmentLevel(Enchantments.INFINITY, bow) > 0; ItemStack ammunition = findArrow(player); int charge = this.getMaxItemUseDuration(bow) - timeLeft; + charge = ForgeEventFactory.onArrowLoose(bow, world, player, charge, !ammunition.isEmpty() || hasInfiniteAmmo); + if (charge < 0 || ammunition.isEmpty() && !hasInfiniteAmmo) { return; } @@ -50,51 +52,65 @@ public void onPlayerStoppedUsing(final ItemStack bow, final World world, } final float velocity = getArrowVelocity(charge); + if (velocity < 0.1F) { return; } final ItemArrow arrowItem = ammunition.getItem() instanceof ItemArrow - ? (ItemArrow) ammunition.getItem() : (ItemArrow) Items.ARROW; + ? (ItemArrow) ammunition.getItem() + : (ItemArrow) Items.ARROW; final boolean infiniteShot = player.capabilities.isCreativeMode || arrowItem.isInfinite(ammunition, bow, player); + if (!world.isRemote) { final EntityArrow projectile = arrowItem.createArrow(world, ammunition, player); + MaterialRangedDamage.applyComponent(projectile, getMMDMaterial()); projectile.shoot(player, player.rotationPitch, player.rotationYaw, 0.0F, velocity * 3.0F, 1.0F); + if (velocity == 1.0F) { projectile.setIsCritical(true); } final int power = EnchantmentHelper.getEnchantmentLevel(Enchantments.POWER, bow); + if (power > 0) { projectile.setDamage(projectile.getDamage() + power * 0.5D + 0.5D); } + final int punch = EnchantmentHelper.getEnchantmentLevel(Enchantments.PUNCH, bow); + if (punch > 0) { projectile.setKnockbackStrength(punch); } + if (EnchantmentHelper.getEnchantmentLevel(Enchantments.FLAME, bow) > 0) { projectile.setFire(100); } bow.damageItem(1, player); + if (infiniteShot) { projectile.pickupStatus = EntityArrow.PickupStatus.CREATIVE_ONLY; } + world.spawnEntity(projectile); } world.playSound(null, player.posX, player.posY, player.posZ, SoundEvents.ENTITY_ARROW_SHOOT, SoundCategory.PLAYERS, 1.0F, 1.0F / (itemRand.nextFloat() * 0.4F + 1.2F) + velocity * 0.5F); + if (!infiniteShot) { ammunition.shrink(1); + if (ammunition.isEmpty()) { player.inventory.deleteStack(ammunition); } } + player.addStat(StatList.getObjectUseStats(this)); } @@ -102,15 +118,19 @@ private static ItemStack findArrow(final EntityPlayer player) { if (isArrowStack(player.getHeldItem(EnumHand.OFF_HAND))) { return player.getHeldItem(EnumHand.OFF_HAND); } + if (isArrowStack(player.getHeldItem(EnumHand.MAIN_HAND))) { return player.getHeldItem(EnumHand.MAIN_HAND); } + for (int slot = 0; slot < player.inventory.getSizeInventory(); slot++) { final ItemStack stack = player.inventory.getStackInSlot(slot); + if (isArrowStack(stack)) { return stack; } } + return ItemStack.EMPTY; } diff --git a/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsCrossbow.java b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsCrossbow.java index 2fe07b11..71ffbd60 100644 --- a/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsCrossbow.java +++ b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsCrossbow.java @@ -23,12 +23,8 @@ import net.minecraftforge.event.ForgeEventFactory; /** - * Base Metals' 1.12 crossbow implementation. - * - *

MMDLib 1.0.0-rc2 creates bolts on the client, leaving the server with no - * projectile to resolve impacts or damage. This retains the MMDLib item and - * ammunition contracts while restoring the server-authoritative firing path - * used by Base Metals 1.10 and later ports.

+ * Fires bolts on the server so their hits deal damage. + * MMDLib's crossbow spawns them only on the client. */ public final class ItemBaseMetalsCrossbow extends ItemMMDCrossbow { @@ -48,20 +44,24 @@ public void onPlayerStoppedUsing(final ItemStack crossbow, final World world, || EnchantmentHelper.getEnchantmentLevel(Enchantments.INFINITY, crossbow) > 0; ItemStack ammunition = findBolt(player); int charge = this.getMaxItemUseDuration(crossbow) - timeLeft; + charge = ForgeEventFactory.onArrowLoose(crossbow, world, player, charge, !ammunition.isEmpty() || hasInfiniteAmmo); + if (charge < 0 || ammunition.isEmpty() && !hasInfiniteAmmo) { return; } if (ammunition.isEmpty()) { ammunition = defaultBolt(); + if (ammunition.isEmpty()) { return; } } final float velocity = getArrowVelocity(charge); + if (velocity < 0.1F) { return; } @@ -69,68 +69,88 @@ public void onPlayerStoppedUsing(final ItemStack crossbow, final World world, final ItemBolt boltItem = (ItemBolt) ammunition.getItem(); final boolean infiniteShot = player.capabilities.isCreativeMode || boltItem.isInfinite(ammunition, crossbow, player); + if (!world.isRemote) { final ItemStack projectileAmmunition = ammunition.copy(); + projectileAmmunition.setCount(1); + final EntityCustomBolt projectile = boltItem.createBolt( world, projectileAmmunition, player); + MaterialRangedDamage.applyComponent(projectile, getMMDMaterial()); projectile.shoot(player, player.rotationPitch, player.rotationYaw, 0.0F, velocity * 3.0F, 1.0F); + if (velocity == 1.0F) { projectile.setIsCritical(true); } final int power = EnchantmentHelper.getEnchantmentLevel(Enchantments.POWER, crossbow); + if (power > 0) { projectile.setDamage(projectile.getDamage() + power * 0.5D + 0.5D); } + final int punch = EnchantmentHelper.getEnchantmentLevel(Enchantments.PUNCH, crossbow); + if (punch > 0) { projectile.setKnockbackStrength(punch); } + if (EnchantmentHelper.getEnchantmentLevel(Enchantments.FLAME, crossbow) > 0) { projectile.setFire(100); } crossbow.damageItem(1, player); + if (infiniteShot) { projectile.pickupStatus = EntityCustomBolt.PickupStatus.CREATIVE_ONLY; } + world.spawnEntity(projectile); } world.playSound(null, player.posX, player.posY, player.posZ, SoundEvents.ENTITY_ARROW_SHOOT, SoundCategory.PLAYERS, 1.0F, 1.0F / (itemRand.nextFloat() * 0.4F + 1.2F) + velocity * 0.5F); + if (!infiniteShot) { ammunition.shrink(1); + if (ammunition.isEmpty()) { player.inventory.deleteStack(ammunition); } } + player.addStat(StatList.getObjectUseStats(this)); } private static ItemStack defaultBolt() { final MMDMaterial iron = Materials.getMaterialByName(MaterialNames.IRON); + return iron.isEmpty() || !iron.hasItem(Names.BOLT) - ? ItemStack.EMPTY : new ItemStack(iron.getItem(Names.BOLT)); + ? ItemStack.EMPTY + : new ItemStack(iron.getItem(Names.BOLT)); } private static ItemStack findBolt(final EntityPlayer player) { if (isBoltStack(player.getHeldItem(EnumHand.OFF_HAND))) { return player.getHeldItem(EnumHand.OFF_HAND); } + if (isBoltStack(player.getHeldItem(EnumHand.MAIN_HAND))) { return player.getHeldItem(EnumHand.MAIN_HAND); } + for (int slot = 0; slot < player.inventory.getSizeInventory(); slot++) { final ItemStack stack = player.inventory.getStackInSlot(slot); + if (isBoltStack(stack)) { return stack; } } + return ItemStack.EMPTY; } diff --git a/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsHoe.java b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsHoe.java index 8427df3e..5acd2f47 100644 --- a/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsHoe.java +++ b/src/main/java/com/mcmoddev/basemetals/items/ItemBaseMetalsHoe.java @@ -5,12 +5,8 @@ import com.mcmoddev.lib.material.MMDMaterial; /** - * Base Metals hoe which exposes the real Forge tool-material name. - * - *

{@link net.minecraft.item.ItemHoe#getMaterialName()} is expected to return - * the backing {@link net.minecraft.item.Item.ToolMaterial} enum constant. The - * MMDLib implementation instead returns the lower-case material identifier, - * which breaks consumers that use the vanilla contract.

+ * Returns the ToolMaterial enum name expected by vanilla and other mods. + * MMDLib returns a lowercase material name instead, which breaks that lookup. */ public final class ItemBaseMetalsHoe extends ItemMMDHoe { diff --git a/src/main/java/com/mcmoddev/basemetals/items/MaterialRangedDamage.java b/src/main/java/com/mcmoddev/basemetals/items/MaterialRangedDamage.java index 5fb5cfe2..6dea684f 100644 --- a/src/main/java/com/mcmoddev/basemetals/items/MaterialRangedDamage.java +++ b/src/main/java/com/mcmoddev/basemetals/items/MaterialRangedDamage.java @@ -4,7 +4,7 @@ import net.minecraft.entity.projectile.EntityArrow; -/** Shared material contribution used by Base Metals ranged weapons. */ +/** Combines the launcher and ammunition materials to calculate shot damage. */ final class MaterialRangedDamage { private static final double NEUTRAL_COMPONENT_DAMAGE = 1.0D; @@ -15,15 +15,13 @@ private MaterialRangedDamage() { } /** - * Replaces one vanilla-neutral launcher or ammunition contribution with the - * supplied material's established base attack damage. - * - * @param projectile projectile whose base damage is being composed - * @param material launcher or ammunition material + * Replaces the vanilla contribution of 1.0 with the material's attack damage. + * Called once for ammunition and once for the launcher, before Power bonuses. */ static void applyComponent(final EntityArrow projectile, final MMDMaterial material) { final double adjustedDamage = projectile.getDamage() - NEUTRAL_COMPONENT_DAMAGE + material.getBaseAttackDamage(); + projectile.setDamage(Math.max(MINIMUM_PROJECTILE_DAMAGE, adjustedDamage)); } } diff --git a/src/main/java/com/mcmoddev/basemetals/loot/ContentModeLootCondition.java b/src/main/java/com/mcmoddev/basemetals/loot/ContentModeLootCondition.java index e09b74e0..a6d7f02f 100644 --- a/src/main/java/com/mcmoddev/basemetals/loot/ContentModeLootCondition.java +++ b/src/main/java/com/mcmoddev/basemetals/loot/ContentModeLootCondition.java @@ -13,7 +13,7 @@ import java.util.Random; -/** Hides Base Metals-owned auxiliary loot entries disallowed by the startup policy. */ +/** Removes restricted items from Base Metals' chest loot. */ public final class ContentModeLootCondition implements LootCondition { public static final ResourceLocation ID = new ResourceLocation(BaseMetals.MODID, "content_policy"); private static boolean registered; diff --git a/src/main/java/com/mcmoddev/basemetals/network/ContentModeMessage.java b/src/main/java/com/mcmoddev/basemetals/network/ContentModeMessage.java index ccd11643..2e48c34c 100644 --- a/src/main/java/com/mcmoddev/basemetals/network/ContentModeMessage.java +++ b/src/main/java/com/mcmoddev/basemetals/network/ContentModeMessage.java @@ -5,7 +5,7 @@ import net.minecraftforge.fml.common.network.ByteBufUtils; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; -/** Client declaration of its effective, startup-latched content mode. */ +/** Sends the client's startup content mode to the server. */ public final class ContentModeMessage implements IMessage { private String serializedMode; diff --git a/src/main/java/com/mcmoddev/basemetals/network/ContentModeNetwork.java b/src/main/java/com/mcmoddev/basemetals/network/ContentModeNetwork.java index f9d05dfb..3d36ebe6 100644 --- a/src/main/java/com/mcmoddev/basemetals/network/ContentModeNetwork.java +++ b/src/main/java/com/mcmoddev/basemetals/network/ContentModeNetwork.java @@ -12,10 +12,9 @@ import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper; import net.minecraftforge.fml.relauncher.Side; -/** Stable network contract that prevents client/server recipe-policy disagreement. */ +/** Rejects connections when the client and server use different content modes. */ public final class ContentModeNetwork { - private static final SimpleNetworkWrapper CHANNEL = - NetworkRegistry.INSTANCE.newSimpleChannel("bm_content_mode"); + private static final SimpleNetworkWrapper CHANNEL = NetworkRegistry.INSTANCE.newSimpleChannel("bm_content_mode"); private static boolean initialized; private ContentModeNetwork() { @@ -36,23 +35,27 @@ public static boolean modesMatch(final ContentMode client, final ContentMode ser return client == server; } - public static final class ServerHandler - implements IMessageHandler { + public static final class ServerHandler implements IMessageHandler { @Override public IMessage onMessage(final ContentModeMessage message, final MessageContext context) { final EntityPlayerMP player = context.getServerHandler().player; + player.getServerWorld().addScheduledTask(() -> { final ContentMode serverMode = BMeConfig.getActiveContentMode(); + if (!message.hasValidMode() || !modesMatch(message.mode(), serverMode)) { final String clientName = message.hasValidMode() - ? message.mode().serializedName() : "invalid"; + ? message.mode().serializedName() + : "invalid"; final String reason = "Base Metals content mode mismatch: server uses '" + serverMode.serializedName() + "' but client uses '" + clientName + "'. Set General/contentMode to the same value and restart Minecraft."; + BaseMetals.logger.warn("Rejecting {}: {}", player.getName(), reason); player.connection.disconnect(new TextComponentString(reason)); } }); + return null; } } diff --git a/src/main/java/com/mcmoddev/basemetals/properties/AdamantineProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/AdamantineProperty.java index 544e3bb2..020535a2 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/AdamantineProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/AdamantineProperty.java @@ -18,14 +18,17 @@ public void apply(ItemStack stack) { @Override public void apply(ItemStack stack, EntityPlayer player) { - if(hasEffect(stack, player)) { + if (hasEffect(stack, player)) { final int level = countArmorPieces(Materials.getMaterialByName(MaterialNames.ADAMANTINE), player) / 2; + if (level == 0) { return; } + if (level > 0) { final PotionEffect protection = new PotionEffect(MobEffects.RESISTANCE, EFFECT_DURATION, level - 1, false, false); + player.addPotionEffect(protection); } } @@ -33,29 +36,29 @@ public void apply(ItemStack stack, EntityPlayer player) { @Override public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { - apply(stack, (EntityPlayer)ent); + if (hasEffect(stack, ent) && ent instanceof EntityPlayer) { + apply(stack, (EntityPlayer) ent); } } @Override public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack + return false; } @Override public boolean hasEffect(ItemStack stack, EntityPlayer player) { MMDMaterial mat = Materials.getMaterialByName(MaterialNames.ADAMANTINE); boolean rv = (stackIsArmorMaterial(stack, mat) - && ((stack.getItem() instanceof IMMDObject) && - (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && - (countArmorPieces(Materials.getMaterialByName(MaterialNames.ADAMANTINE),player) > 0); + && ((stack.getItem() instanceof IMMDObject) + && (((IMMDObject) stack.getItem()).getMMDMaterial() == mat))) + && (countArmorPieces(Materials.getMaterialByName(MaterialNames.ADAMANTINE), player) > 0); return rv; } @Override public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; + return ent instanceof EntityPlayer ? hasEffect(stack, (EntityPlayer) ent) : false; } } diff --git a/src/main/java/com/mcmoddev/basemetals/properties/AdamantineToolProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/AdamantineToolProperty.java index f0f80e07..8078bcb9 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/AdamantineToolProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/AdamantineToolProperty.java @@ -19,14 +19,15 @@ public void apply(ItemStack stack) { @Override public void apply(ItemStack stack, EntityPlayer player) { - apply(stack, (EntityLivingBase)player); + apply(stack, (EntityLivingBase) player); } @Override public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent)) { + if (hasEffect(stack, ent)) { if (ent.getMaxHealth() > 20f) { final DamageSource extraDamage = DamageSource.GENERIC; + ent.attackEntityFrom(extraDamage, 4f); } } @@ -34,22 +35,22 @@ public void apply(ItemStack stack, EntityLivingBase ent) { @Override public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack + return false; } @Override public boolean hasEffect(ItemStack stack, EntityPlayer player) { - return hasEffect(stack, (EntityLivingBase)player); + return hasEffect(stack, (EntityLivingBase) player); } @Override public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - if(stack.getItem() instanceof IMMDObject) { - MMDMaterial mat = ((IMMDObject)stack.getItem()).getMMDMaterial(); + if (stack.getItem() instanceof IMMDObject) { + MMDMaterial mat = ((IMMDObject) stack.getItem()).getMMDMaterial(); + return MaterialNames.ADAMANTINE.equals(mat.getName()) && (ent.getMaxHealth() > 20f); } else { return false; } } - } diff --git a/src/main/java/com/mcmoddev/basemetals/properties/AquariumProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/AquariumProperty.java index d36c702d..785fa199 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/AquariumProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/AquariumProperty.java @@ -18,13 +18,16 @@ public void apply(ItemStack stack) { @Override public void apply(ItemStack stack, EntityPlayer player) { - if(hasEffect(stack, player)) { + if (hasEffect(stack, player)) { if (hasFullSuit(player, MaterialNames.AQUARIUM) && player.isInWater()) { final PotionEffect waterBreathing = new PotionEffect(MobEffects.WATER_BREATHING, EFFECT_DURATION, 0, false, false); + player.addPotionEffect(waterBreathing); + final PotionEffect protection = new PotionEffect(MobEffects.RESISTANCE, EFFECT_DURATION, 0, false, false); + player.addPotionEffect(protection); player.removePotionEffect(MobEffects.MINING_FATIGUE); } @@ -33,29 +36,29 @@ public void apply(ItemStack stack, EntityPlayer player) { @Override public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { - apply(stack, (EntityPlayer)ent); + if (hasEffect(stack, ent) && ent instanceof EntityPlayer) { + apply(stack, (EntityPlayer) ent); } } @Override public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack + return false; } @Override public boolean hasEffect(ItemStack stack, EntityPlayer player) { MMDMaterial mat = Materials.getMaterialByName(MaterialNames.AQUARIUM); boolean rv = (stackIsArmorMaterial(stack, mat) - && ((stack.getItem() instanceof IMMDObject) && - (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && - (countArmorPieces(Materials.getMaterialByName(MaterialNames.AQUARIUM),player) > 0); + && ((stack.getItem() instanceof IMMDObject) + && (((IMMDObject) stack.getItem()).getMMDMaterial() == mat))) + && (countArmorPieces(Materials.getMaterialByName(MaterialNames.AQUARIUM), player) > 0); return rv; } @Override public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; + return ent instanceof EntityPlayer ? hasEffect(stack, (EntityPlayer) ent) : false; } } diff --git a/src/main/java/com/mcmoddev/basemetals/properties/AquariumToolProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/AquariumToolProperty.java index 449c6a0d..11afd584 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/AquariumToolProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/AquariumToolProperty.java @@ -19,14 +19,15 @@ public void apply(ItemStack stack) { @Override public void apply(ItemStack stack, EntityPlayer player) { - apply(stack, (EntityLivingBase)player); + apply(stack, (EntityLivingBase) player); } @Override public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent)) { + if (hasEffect(stack, ent)) { if (ent.canBreatheUnderwater()) { final DamageSource extraDamage = DamageSource.GENERIC; + ent.attackEntityFrom(extraDamage, 4f); } } @@ -34,22 +35,22 @@ public void apply(ItemStack stack, EntityLivingBase ent) { @Override public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack + return false; } @Override public boolean hasEffect(ItemStack stack, EntityPlayer player) { - return hasEffect(stack, (EntityLivingBase)player); + return hasEffect(stack, (EntityLivingBase) player); } @Override public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - if(stack.getItem() instanceof IMMDObject) { - MMDMaterial mat = ((IMMDObject)stack.getItem()).getMMDMaterial(); + if (stack.getItem() instanceof IMMDObject) { + MMDMaterial mat = ((IMMDObject) stack.getItem()).getMMDMaterial(); + return MaterialNames.AQUARIUM.equals(mat.getName()) && (ent.canBreatheUnderwater()); } else { return false; } } - } diff --git a/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertiesHelper.java b/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertiesHelper.java index 8f75be15..47693282 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertiesHelper.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertiesHelper.java @@ -15,29 +15,30 @@ public final class BMEPropertiesHelper { private static final String ARMOR = ".armor"; private static final String TOOL = ".tool"; - /** Returns the special tool-effect tooltip for a material, when it has one. */ @SideOnly(Side.CLIENT) public static List addToolSpecialPropertiesToolTip(final String materialName) { List rv = new ArrayList<>(); + switch (materialName) { - case MaterialNames.ADAMANTINE: + case MaterialNames.ADAMANTINE : rv.add(I18n.format(TOOLTIP + MaterialNames.ADAMANTINE + TOOL, 4)); break; - case MaterialNames.AQUARIUM: + case MaterialNames.AQUARIUM : rv.add(I18n.format(TOOLTIP + MaterialNames.AQUARIUM + TOOL, 4)); break; - case MaterialNames.COLDIRON: + case MaterialNames.COLDIRON : rv.add(I18n.format(TOOLTIP + MaterialNames.COLDIRON + TOOL, 3)); break; - case MaterialNames.MITHRIL: + case MaterialNames.MITHRIL : rv.add(I18n.format(TOOLTIP + MaterialNames.MITHRIL + TOOL)); break; - case MaterialNames.STARSTEEL: + case MaterialNames.STARSTEEL : rv.add(I18n.format(TOOLTIP + MaterialNames.STARSTEEL + TOOL, 10)); break; - default: + default : } + return rv; } @@ -45,24 +46,26 @@ public static List addToolSpecialPropertiesToolTip(final String material @SideOnly(Side.CLIENT) public static List addArmorSpecialPropertiesToolTip(final String materialName) { List rv = new ArrayList<>(); + switch (materialName) { - case MaterialNames.ADAMANTINE: + case MaterialNames.ADAMANTINE : rv.add(I18n.format(TOOLTIP + MaterialNames.ADAMANTINE + ARMOR, 4)); break; - case MaterialNames.AQUARIUM: + case MaterialNames.AQUARIUM : rv.add(I18n.format(TOOLTIP + MaterialNames.AQUARIUM + ARMOR, 4)); break; - case MaterialNames.COLDIRON: + case MaterialNames.COLDIRON : rv.add(I18n.format(TOOLTIP + MaterialNames.COLDIRON + ARMOR, 3)); break; - case MaterialNames.MITHRIL: + case MaterialNames.MITHRIL : rv.add(I18n.format(TOOLTIP + MaterialNames.MITHRIL + ARMOR)); break; - case MaterialNames.STARSTEEL: + case MaterialNames.STARSTEEL : rv.add(I18n.format(TOOLTIP + MaterialNames.STARSTEEL + ARMOR, 10)); break; - default: + default : } + return rv; } } diff --git a/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertyBase.java b/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertyBase.java index be36531e..1398db97 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertyBase.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/BMEPropertyBase.java @@ -15,7 +15,7 @@ public abstract class BMEPropertyBase extends MMDMaterialPropertyBase { protected static final int EFFECT_DURATION = 45; protected static int countArmorPieces(final MMDMaterial mat, final EntityPlayer player) { - return (int) Arrays.stream(new EntityEquipmentSlot[] { + return (int) Arrays.stream(new EntityEquipmentSlot[]{ EntityEquipmentSlot.HEAD, EntityEquipmentSlot.CHEST, EntityEquipmentSlot.LEGS, @@ -30,7 +30,7 @@ protected static boolean hasFullSuit(final EntityPlayer player, final String mat final MMDMaterial material = Materials.getMaterialByName(materialName); return ((player.getItemStackFromSlot(EntityEquipmentSlot.HEAD).getItem() == material - .getItem(Names.HELMET)) + .getItem(Names.HELMET)) && (player.getItemStackFromSlot(EntityEquipmentSlot.CHEST).getItem() == material .getItem(Names.CHESTPLATE)) && (player.getItemStackFromSlot(EntityEquipmentSlot.LEGS).getItem() == material diff --git a/src/main/java/com/mcmoddev/basemetals/properties/ColdIronProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/ColdIronProperty.java index 0307f9a1..fc7787ee 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/ColdIronProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/ColdIronProperty.java @@ -18,10 +18,11 @@ public void apply(ItemStack stack) { @Override public void apply(ItemStack stack, EntityPlayer player) { - if(hasEffect(stack, player)) { + if (hasEffect(stack, player)) { if (hasFullSuit(player, MaterialNames.COLDIRON)) { final PotionEffect fireProtection = new PotionEffect(MobEffects.FIRE_RESISTANCE, EFFECT_DURATION, 0, false, false); + player.addPotionEffect(fireProtection); } } @@ -29,29 +30,29 @@ public void apply(ItemStack stack, EntityPlayer player) { @Override public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { - apply(stack, (EntityPlayer)ent); + if (hasEffect(stack, ent) && ent instanceof EntityPlayer) { + apply(stack, (EntityPlayer) ent); } } @Override public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack + return false; } @Override public boolean hasEffect(ItemStack stack, EntityPlayer player) { MMDMaterial mat = Materials.getMaterialByName(MaterialNames.COLDIRON); boolean rv = (stackIsArmorMaterial(stack, mat) - && ((stack.getItem() instanceof IMMDObject) && - (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && - (countArmorPieces(Materials.getMaterialByName(MaterialNames.COLDIRON),player) > 0); + && ((stack.getItem() instanceof IMMDObject) + && (((IMMDObject) stack.getItem()).getMMDMaterial() == mat))) + && (countArmorPieces(Materials.getMaterialByName(MaterialNames.COLDIRON), player) > 0); return rv; } @Override public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; + return ent instanceof EntityPlayer ? hasEffect(stack, (EntityPlayer) ent) : false; } } diff --git a/src/main/java/com/mcmoddev/basemetals/properties/ColdIronToolProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/ColdIronToolProperty.java index 9222c376..11889991 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/ColdIronToolProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/ColdIronToolProperty.java @@ -19,35 +19,36 @@ public void apply(ItemStack stack) { @Override public void apply(ItemStack stack, EntityPlayer player) { - apply(stack, (EntityLivingBase)player); + apply(stack, (EntityLivingBase) player); } @Override public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent)) { + if (hasEffect(stack, ent)) { final DamageSource extraDamage = DamageSource.GENERIC; + ent.attackEntityFrom(extraDamage, 3f); } } @Override public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack + return false; } @Override public boolean hasEffect(ItemStack stack, EntityPlayer player) { - return hasEffect(stack, (EntityLivingBase)player); + return hasEffect(stack, (EntityLivingBase) player); } @Override public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - if(stack.getItem() instanceof IMMDObject) { - MMDMaterial mat = ((IMMDObject)stack.getItem()).getMMDMaterial(); + if (stack.getItem() instanceof IMMDObject) { + MMDMaterial mat = ((IMMDObject) stack.getItem()).getMMDMaterial(); + return MaterialNames.COLDIRON.equals(mat.getName()) && ent.isImmuneToFire(); } else { return false; } } - } diff --git a/src/main/java/com/mcmoddev/basemetals/properties/LeadProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/LeadProperty.java index b7ae40a8..ba999e84 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/LeadProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/LeadProperty.java @@ -18,14 +18,17 @@ public void apply(ItemStack stack) { @Override public void apply(ItemStack stack, EntityPlayer player) { - if(hasEffect(stack, player)) { + if (hasEffect(stack, player)) { final int level = countArmorPieces(Materials.getMaterialByName(MaterialNames.LEAD), player) / 2; + if (level == 0) { return; } + if (level > 0) { final PotionEffect speedLoss = new PotionEffect(MobEffects.SLOWNESS, EFFECT_DURATION, level - 1, false, false); + player.addPotionEffect(speedLoss); } } @@ -33,29 +36,29 @@ public void apply(ItemStack stack, EntityPlayer player) { @Override public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { - apply(stack, (EntityPlayer)ent); + if (hasEffect(stack, ent) && ent instanceof EntityPlayer) { + apply(stack, (EntityPlayer) ent); } } @Override public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack + return false; } @Override public boolean hasEffect(ItemStack stack, EntityPlayer player) { MMDMaterial mat = Materials.getMaterialByName(MaterialNames.LEAD); boolean rv = (stackIsArmorMaterial(stack, mat) - && ((stack.getItem() instanceof IMMDObject) && - (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && - (countArmorPieces(Materials.getMaterialByName(MaterialNames.LEAD),player) > 0); + && ((stack.getItem() instanceof IMMDObject) + && (((IMMDObject) stack.getItem()).getMMDMaterial() == mat))) + && (countArmorPieces(Materials.getMaterialByName(MaterialNames.LEAD), player) > 0); return rv; } @Override public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; + return ent instanceof EntityPlayer ? hasEffect(stack, (EntityPlayer) ent) : false; } } diff --git a/src/main/java/com/mcmoddev/basemetals/properties/MithrilProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/MithrilProperty.java index 484ffed5..260a70cf 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/MithrilProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/MithrilProperty.java @@ -20,53 +20,56 @@ public class MithrilProperty extends BMEPropertyBase { public void apply(ItemStack stack) { } - @Override - public void apply(ItemStack stack, EntityPlayer player) { - if(hasEffect(stack, player)) { - if (hasFullSuit(player, MaterialNames.MITHRIL)) { - // Collect first because removing effects while iterating would modify the source collection. - final List removeList = new LinkedList<>(); - final Iterator effectIterator = player.getActivePotionEffects() - .iterator(); - while (effectIterator.hasNext()) { - final PotionEffect pe = effectIterator.next(); - final Potion p = pe.getPotion(); - if (p.isBadEffect()) { - removeList.add(p); - } - } - for (final Potion p : removeList) { - player.removePotionEffect(p); + @Override + public void apply(ItemStack stack, EntityPlayer player) { + if (hasEffect(stack, player)) { + if (hasFullSuit(player, MaterialNames.MITHRIL)) { + // Collect harmful effects first; removing them during iteration is unsafe. + final List removeList = new LinkedList<>(); + final Iterator effectIterator = player.getActivePotionEffects() + .iterator(); + + while (effectIterator.hasNext()) { + final PotionEffect pe = effectIterator.next(); + final Potion p = pe.getPotion(); + + if (p.isBadEffect()) { + removeList.add(p); + } + } + + for (final Potion p : removeList) { + player.removePotionEffect(p); + } + } } - } } - } @Override public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { - apply(stack, (EntityPlayer)ent); + if (hasEffect(stack, ent) && ent instanceof EntityPlayer) { + apply(stack, (EntityPlayer) ent); } } @Override public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack + return false; } @Override public boolean hasEffect(ItemStack stack, EntityPlayer player) { MMDMaterial mat = Materials.getMaterialByName(MaterialNames.MITHRIL); boolean rv = (stackIsArmorMaterial(stack, mat) - && ((stack.getItem() instanceof IMMDObject) && - (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && - (countArmorPieces(Materials.getMaterialByName(MaterialNames.MITHRIL),player) > 0); + && ((stack.getItem() instanceof IMMDObject) + && (((IMMDObject) stack.getItem()).getMMDMaterial() == mat))) + && (countArmorPieces(Materials.getMaterialByName(MaterialNames.MITHRIL), player) > 0); return rv; } @Override public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; + return ent instanceof EntityPlayer ? hasEffect(stack, (EntityPlayer) ent) : false; } } diff --git a/src/main/java/com/mcmoddev/basemetals/properties/MithrilToolProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/MithrilToolProperty.java index ed49f6ce..f0247a4e 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/MithrilToolProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/MithrilToolProperty.java @@ -21,15 +21,16 @@ public void apply(ItemStack stack) { @Override public void apply(ItemStack stack, EntityPlayer player) { - apply(stack, (EntityLivingBase)player); + apply(stack, (EntityLivingBase) player); } @Override public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent)) { + if (hasEffect(stack, ent)) { if (ent.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD) { final PotionEffect wither = new PotionEffect(MobEffects.WITHER, 60, 3); final PotionEffect blind = new PotionEffect(MobEffects.BLINDNESS, 60, 1); + ent.addPotionEffect(wither); ent.addPotionEffect(blind); } @@ -38,22 +39,23 @@ public void apply(ItemStack stack, EntityLivingBase ent) { @Override public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack + return false; } @Override public boolean hasEffect(ItemStack stack, EntityPlayer player) { - return hasEffect(stack, (EntityLivingBase)player); + return hasEffect(stack, (EntityLivingBase) player); } @Override public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - if(stack.getItem() instanceof IMMDObject) { - MMDMaterial mat = ((IMMDObject)stack.getItem()).getMMDMaterial(); - return MaterialNames.MITHRIL.equals(mat.getName()) && (ent.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD); + if (stack.getItem() instanceof IMMDObject) { + MMDMaterial mat = ((IMMDObject) stack.getItem()).getMMDMaterial(); + + return MaterialNames.MITHRIL.equals(mat.getName()) + && (ent.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD); } else { return false; } } - } diff --git a/src/main/java/com/mcmoddev/basemetals/properties/StarSteelProperty.java b/src/main/java/com/mcmoddev/basemetals/properties/StarSteelProperty.java index 2283a77b..864daf3f 100755 --- a/src/main/java/com/mcmoddev/basemetals/properties/StarSteelProperty.java +++ b/src/main/java/com/mcmoddev/basemetals/properties/StarSteelProperty.java @@ -18,17 +18,22 @@ public void apply(ItemStack stack) { @Override public void apply(ItemStack stack, EntityPlayer player) { - if(hasEffect(stack, player)) { + if (hasEffect(stack, player)) { final int num = countArmorPieces(Materials.getMaterialByName(MaterialNames.STARSTEEL), player); + if (num == 0) { return; } + final PotionEffect jumpBoost = new PotionEffect(MobEffects.JUMP_BOOST, EFFECT_DURATION, num - 1, false, false); + player.addPotionEffect(jumpBoost); + if (num > 1) { final PotionEffect speedBoost = new PotionEffect(MobEffects.SPEED, EFFECT_DURATION, num - 2, false, false); + player.addPotionEffect(speedBoost); } } @@ -36,29 +41,29 @@ public void apply(ItemStack stack, EntityPlayer player) { @Override public void apply(ItemStack stack, EntityLivingBase ent) { - if(hasEffect(stack, ent) && ent instanceof EntityPlayer) { - apply(stack, (EntityPlayer)ent); + if (hasEffect(stack, ent) && ent instanceof EntityPlayer) { + apply(stack, (EntityPlayer) ent); } } @Override public boolean hasEffect(ItemStack stack) { - return false; // no effect for just the stack + return false; } @Override public boolean hasEffect(ItemStack stack, EntityPlayer player) { MMDMaterial mat = Materials.getMaterialByName(MaterialNames.STARSTEEL); boolean rv = (stackIsArmorMaterial(stack, mat) - && ((stack.getItem() instanceof IMMDObject) && - (((IMMDObject)stack.getItem()).getMMDMaterial() == mat))) && - (countArmorPieces(Materials.getMaterialByName(MaterialNames.STARSTEEL),player) > 0); + && ((stack.getItem() instanceof IMMDObject) + && (((IMMDObject) stack.getItem()).getMMDMaterial() == mat))) + && (countArmorPieces(Materials.getMaterialByName(MaterialNames.STARSTEEL), player) > 0); return rv; } @Override public boolean hasEffect(ItemStack stack, EntityLivingBase ent) { - return ent instanceof EntityPlayer?hasEffect(stack, (EntityPlayer)ent):false; + return ent instanceof EntityPlayer ? hasEffect(stack, (EntityPlayer) ent) : false; } } diff --git a/src/main/java/com/mcmoddev/basemetals/proxy/ClientProxy.java b/src/main/java/com/mcmoddev/basemetals/proxy/ClientProxy.java index 3f707e3c..3844525b 100644 --- a/src/main/java/com/mcmoddev/basemetals/proxy/ClientProxy.java +++ b/src/main/java/com/mcmoddev/basemetals/proxy/ClientProxy.java @@ -59,12 +59,14 @@ public static void registerModels(final ModelRegistryEvent event) { if (!name.endsWith(Names.ANVIL.toString())) { RegistrationHelper.registerItemRender(name); } else { - final String[] names = new String[] { "intact", "slightly_damaged", - "very_damaged" }; + final String[] names = new String[]{"intact", "slightly_damaged", + "very_damaged"}; final Item item = Items.getItemByName(name); + for (int i = 0; i < 3; i++) { final ResourceLocation rl = new ResourceLocation(BaseMetals.MODID, String.format("%s_%s", name, names[i])); + ModelLoader.setCustomModelResourceLocation(item, i, new ModelResourceLocation(rl, "inventory")); } @@ -89,11 +91,12 @@ public void init(final FMLInitializationEvent event) { super.init(event); WorldSettingsExtensionRegistry.registerConfigScreen(BaseMetals.MODID, BaseMetalsConfigScreen::new); + if (Loader.isModLoaded("waila")) { com.mcmoddev.lib.waila.Waila.init(); } } - + @Override @SideOnly(Side.CLIENT) public World getWorld(@Nullable final int dimension) { diff --git a/src/main/java/com/mcmoddev/basemetals/proxy/CommonProxy.java b/src/main/java/com/mcmoddev/basemetals/proxy/CommonProxy.java index 21d7cc54..5141d609 100644 --- a/src/main/java/com/mcmoddev/basemetals/proxy/CommonProxy.java +++ b/src/main/java/com/mcmoddev/basemetals/proxy/CommonProxy.java @@ -1,6 +1,5 @@ package com.mcmoddev.basemetals.proxy; - import javax.annotation.Nullable; import com.mcmoddev.basemetals.BaseMetals; @@ -20,6 +19,7 @@ import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; + /** Common setup shared by the client and dedicated server. */ public class CommonProxy { @@ -60,9 +60,10 @@ public void init(final FMLInitializationEvent event) { ItemGroups.setupIcons(MaterialNames.STARSTEEL); } + public void postInit(final FMLPostInitializationEvent event) { } - + public World getWorld(@Nullable final int dimension) { return null; } diff --git a/src/main/java/com/mcmoddev/basemetals/recipe/ContentAcquisitionFilters.java b/src/main/java/com/mcmoddev/basemetals/recipe/ContentAcquisitionFilters.java index 319206e1..8b7a7bfa 100644 --- a/src/main/java/com/mcmoddev/basemetals/recipe/ContentAcquisitionFilters.java +++ b/src/main/java/com/mcmoddev/basemetals/recipe/ContentAcquisitionFilters.java @@ -15,16 +15,18 @@ import java.util.List; import java.util.Map; -/** Applies the latched mode to Base Metals-owned acquisition registries. */ +/** Filters crafting, smelting, and crushing recipes for the selected content mode. */ public final class ContentAcquisitionFilters { private ContentAcquisitionFilters() { } public static void apply(final RegistryEvent.Register event) { final ContentPolicy policy = ContentPolicy.active(); + if (policy.mode() == ContentMode.HIGH_FANTASY) { return; } + wrapCraftingRecipes(event, policy); filterFurnaceRecipes(policy); filterCrusherRecipes(policy); @@ -33,14 +35,17 @@ public static void apply(final RegistryEvent.Register event) { private static void wrapCraftingRecipes(final RegistryEvent.Register event, final ContentPolicy policy) { final List recipes = new ArrayList<>(); + for (final IRecipe recipe : event.getRegistry()) { if (recipe.getRegistryName() != null && BaseMetals.MODID.equals(recipe.getRegistryName().getNamespace())) { recipes.add(recipe); } } + for (final IRecipe recipe : recipes) { final PolicyRecipe wrapped = new PolicyRecipe(recipe, policy); + if (!wrapped.isAllowed()) { event.getRegistry().register(wrapped); } @@ -49,8 +54,8 @@ private static void wrapCraftingRecipes(final RegistryEvent.Register ev private static void filterFurnaceRecipes(final ContentPolicy policy) { final Map recipes = FurnaceRecipes.instance().getSmeltingList(); - final List> snapshot = - new ArrayList<>(recipes.entrySet()); + final List> snapshot = new ArrayList<>(recipes.entrySet()); + for (final Map.Entry recipe : snapshot) { if (!policy.allows(recipe.getValue())) { recipes.remove(recipe.getKey()); @@ -60,9 +65,11 @@ private static void filterFurnaceRecipes(final ContentPolicy policy) { private static void filterCrusherRecipes(final ContentPolicy policy) { final List recipes = CrusherRecipeRegistry.getAll(); + for (final ICrusherRecipe recipe : recipes) { if (!policy.allows(recipe.getOutput())) { final ResourceLocation id = recipe.getRegistryName(); + if (id != null) { CrusherRecipeRegistry.removeByName(id); CrusherRecipeRegistry.getInstance().register( diff --git a/src/main/java/com/mcmoddev/basemetals/recipe/PlateRepairFactory.java b/src/main/java/com/mcmoddev/basemetals/recipe/PlateRepairFactory.java new file mode 100644 index 00000000..b8da4585 --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/recipe/PlateRepairFactory.java @@ -0,0 +1,63 @@ +package com.mcmoddev.basemetals.recipe; + +import java.util.Locale; + +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import com.mcmoddev.lib.data.Names; +import com.mcmoddev.lib.init.Materials; +import com.mcmoddev.lib.material.MMDMaterial; +import com.mcmoddev.lib.util.Oredicts; + +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.JsonUtils; +import net.minecraftforge.common.crafting.IRecipeFactory; +import net.minecraftforge.common.crafting.JsonContext; + +/** Reads the material and armor type from a plate-repair recipe. */ +public final class PlateRepairFactory implements IRecipeFactory { + @Override + public IRecipe parse(final JsonContext context, final JsonObject json) { + final String materialName = JsonUtils.getString(json, "material"); + final MMDMaterial material = Materials.getMaterialByName( + materialName.toLowerCase(Locale.ROOT)); + + if (material == null || material.isEmpty()) { + throw new JsonSyntaxException("Unknown plate-repair material " + materialName); + } + + final String armorType = JsonUtils.getString(json, "armorType").toLowerCase(Locale.ROOT); + final Names form; + + switch (armorType) { + case "boots" : + form = Names.BOOTS; + break; + case "chestplate" : + form = Names.CHESTPLATE; + break; + case "helmet" : + form = Names.HELMET; + break; + case "leggings" : + form = Names.LEGGINGS; + break; + case "shield" : + form = Names.SHIELD; + break; + default : + throw new JsonSyntaxException("Unknown plate-repair armor type " + armorType); + } + + final ItemStack target = material.getItemStack(form); + + if (target.isEmpty()) { + throw new JsonSyntaxException("Missing plate-repair target " + materialName + + " " + armorType); + } + + return new PlateRepairRecipe(material, form, target.getItem(), + Oredicts.PLATE + material.getCapitalizedName()); + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/recipe/PlateRepairRecipe.java b/src/main/java/com/mcmoddev/basemetals/recipe/PlateRepairRecipe.java new file mode 100644 index 00000000..b874b7ba --- /dev/null +++ b/src/main/java/com/mcmoddev/basemetals/recipe/PlateRepairRecipe.java @@ -0,0 +1,100 @@ +package com.mcmoddev.basemetals.recipe; + +import com.mcmoddev.lib.data.Names; +import com.mcmoddev.lib.material.MMDMaterial; +import com.mcmoddev.lib.recipe.RepairRecipeBase; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.util.NonNullList; +import net.minecraft.world.World; +import net.minecraftforge.oredict.OreDictionary; +import net.minecraftforge.oredict.OreIngredient; + +/** Fully repairs one damaged armor piece or shield using one matching plate. */ +public final class PlateRepairRecipe extends RepairRecipeBase { + private final Item target; + private final String plateOre; + private final NonNullList ingredients; + + public PlateRepairRecipe(final MMDMaterial material, final Names form, + final Item target, final String plateOre) { + // Extending RepairRecipeBase keeps MMDLib from counting a repair as + // a way to produce new material. + super(material, form); + this.target = target; + this.plateOre = plateOre; + this.ingredients = NonNullList.create(); + this.ingredients.add(Ingredient.fromStacks(new ItemStack(target))); + this.ingredients.add(new OreIngredient(plateOre)); + } + + @Override + public boolean matches(final InventoryCrafting inventory, final World world) { + boolean foundTarget = false; + boolean foundPlate = false; + + for (int slot = 0; slot < inventory.getSizeInventory(); slot++) { + final ItemStack stack = inventory.getStackInSlot(slot); + + if (stack.isEmpty()) { + continue; + } + + if (stack.getItem() == target && stack.getItemDamage() > 0 && !foundTarget) { + foundTarget = true; + } else if (!foundPlate && OreDictionary.containsMatch(false, + OreDictionary.getOres(plateOre), stack)) { + foundPlate = true; + } else { + return false; + } + } + + return foundTarget && foundPlate; + } + + @Override + public ItemStack getCraftingResult(final InventoryCrafting inventory) { + if (!matches(inventory, null)) { + return ItemStack.EMPTY; + } + + for (int slot = 0; slot < inventory.getSizeInventory(); slot++) { + final ItemStack stack = inventory.getStackInSlot(slot); + + if (!stack.isEmpty() && stack.getItem() == target) { + final ItemStack repaired = stack.copy(); + + repaired.setCount(1); + repaired.setItemDamage(0); + + return repaired; + } + } + + return ItemStack.EMPTY; + } + + @Override + public boolean canFit(final int width, final int height) { + return width * height >= 2; + } + + @Override + public ItemStack getRecipeOutput() { + return new ItemStack(target); + } + + @Override + public NonNullList getIngredients() { + return ingredients; + } + + @Override + public boolean isDynamic() { + return true; + } +} diff --git a/src/main/java/com/mcmoddev/basemetals/recipe/PolicyCrusherRecipe.java b/src/main/java/com/mcmoddev/basemetals/recipe/PolicyCrusherRecipe.java index dcf76b3f..8bf9d7f1 100644 --- a/src/main/java/com/mcmoddev/basemetals/recipe/PolicyCrusherRecipe.java +++ b/src/main/java/com/mcmoddev/basemetals/recipe/PolicyCrusherRecipe.java @@ -8,10 +8,7 @@ import java.util.Collections; import java.util.List; -/** - * Retains a crusher recipe's persistent registry identity while making a - * policy-restricted acquisition route non-matching and invisible. - */ +/** Disables a crusher recipe without removing its saved registry name. */ final class PolicyCrusherRecipe extends IForgeRegistryEntry.Impl implements ICrusherRecipe { diff --git a/src/main/java/com/mcmoddev/basemetals/recipe/PolicyRecipe.java b/src/main/java/com/mcmoddev/basemetals/recipe/PolicyRecipe.java index 58777d9b..d91110c4 100644 --- a/src/main/java/com/mcmoddev/basemetals/recipe/PolicyRecipe.java +++ b/src/main/java/com/mcmoddev/basemetals/recipe/PolicyRecipe.java @@ -8,15 +8,18 @@ import net.minecraft.world.World; import net.minecraftforge.registries.IForgeRegistryEntry; -/** Keeps recipe registry identity stable while disabling acquisition in restricted modes. */ +/** Disables restricted recipes without removing their saved registry names. */ final class PolicyRecipe extends IForgeRegistryEntry.Impl implements IRecipe { private final IRecipe delegate; private final boolean allowed; PolicyRecipe(final IRecipe delegate, final ContentPolicy policy) { this.delegate = delegate; + final ItemStack output = delegate.getRecipeOutput(); - this.allowed = !output.isEmpty() ? policy.allows(output) + + this.allowed = !output.isEmpty() + ? policy.allows(output) : policy.allowsRecipeId(delegate.getRegistryName()); setRegistryName(delegate.getRegistryName()); } diff --git a/src/main/java/com/mcmoddev/basemetals/util/BMeConfig.java b/src/main/java/com/mcmoddev/basemetals/util/BMeConfig.java index 43ad3632..8e2bba81 100644 --- a/src/main/java/com/mcmoddev/basemetals/util/BMeConfig.java +++ b/src/main/java/com/mcmoddev/basemetals/util/BMeConfig.java @@ -22,7 +22,7 @@ import java.util.List; import java.util.Map; -/** Owns the legacy configuration file and the startup-latched content policy. */ +/** Loads BaseMetals.cfg and keeps the content mode fixed until restart. */ public final class BMeConfig extends Config { private static final Logger LOGGER = LogManager.getFormatterLogger("basemetals"); @@ -42,6 +42,7 @@ public final class BMeConfig extends Config { private static final Map GENERATED_ORE_RULES; static { final Map rules = new LinkedHashMap<>(); + rules.put(MaterialNames.COLDIRON, "basemetals:legacy/coldiron_ore"); rules.put(MaterialNames.ADAMANTINE, "basemetals:legacy/adamantine_ore"); rules.put(MaterialNames.STARSTEEL, "basemetals:legacy/starsteel_ore"); @@ -57,46 +58,45 @@ public final class BMeConfig extends Config { } private static final MaterialConfigOptions[] MATERIAL_CONFIG_OPTIONS = new MaterialConfigOptions[]{ - // Base Metals material switches. - new MaterialConfigOptions(MaterialNames.ADAMANTINE, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.ANTIMONY, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.AQUARIUM, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.BISMUTH, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.BRASS, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.BRONZE, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.COLDIRON, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.COPPER, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.CUPRONICKEL, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.ELECTRUM, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.INVAR, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.LEAD, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.MERCURY, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.MITHRIL, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.NICKEL, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.PEWTER, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.PLATINUM, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.SILVER, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.STARSTEEL, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.STEEL, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.TIN, false, true, true, true, true), - new MaterialConfigOptions(MaterialNames.ZINC, false, true, true, true, true), - - // Vanilla Bits. These entries were present in the 2.5.0 release and are - // required before MMDLib fires the material item/block registration events. - new MaterialConfigOptions(MaterialNames.CHARCOAL, true, true, true, true), - new MaterialConfigOptions(MaterialNames.COAL, true, true, true, true), - new MaterialConfigOptions(MaterialNames.DIAMOND, true, true, true, true), - new MaterialConfigOptions(MaterialNames.EMERALD, true, true, true, true), - new MaterialConfigOptions(MaterialNames.GOLD, true, true, true, true), - new MaterialConfigOptions(MaterialNames.IRON, true, true, true, true), - new MaterialConfigOptions(MaterialNames.STONE, true, true, false, false), - new MaterialConfigOptions(MaterialNames.WOOD, true, true, false, false), - new MaterialConfigOptions(MaterialNames.ENDER, true, true, true, true), - new MaterialConfigOptions(MaterialNames.QUARTZ, true, true, true, true), - new MaterialConfigOptions(MaterialNames.OBSIDIAN, true, true, true, true), - new MaterialConfigOptions(MaterialNames.LAPIS, true, true, false, false), - new MaterialConfigOptions(MaterialNames.PRISMARINE, true, true, true, true), - new MaterialConfigOptions(MaterialNames.REDSTONE, true, true, true, true), + // Base Metals material switches. + new MaterialConfigOptions(MaterialNames.ADAMANTINE, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.ANTIMONY, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.AQUARIUM, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.BISMUTH, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.BRASS, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.BRONZE, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.COLDIRON, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.COPPER, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.CUPRONICKEL, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.ELECTRUM, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.INVAR, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.LEAD, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.MERCURY, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.MITHRIL, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.NICKEL, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.PEWTER, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.PLATINUM, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.SILVER, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.STARSTEEL, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.STEEL, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.TIN, false, true, true, true, true), + new MaterialConfigOptions(MaterialNames.ZINC, false, true, true, true, true), + + // Load Vanilla Bits settings before MMDLib registers their items and blocks. + new MaterialConfigOptions(MaterialNames.CHARCOAL, true, true, true, true), + new MaterialConfigOptions(MaterialNames.COAL, true, true, true, true), + new MaterialConfigOptions(MaterialNames.DIAMOND, true, true, true, true), + new MaterialConfigOptions(MaterialNames.EMERALD, true, true, true, true), + new MaterialConfigOptions(MaterialNames.GOLD, true, true, true, true), + new MaterialConfigOptions(MaterialNames.IRON, true, true, true, true), + new MaterialConfigOptions(MaterialNames.STONE, true, true, false, false), + new MaterialConfigOptions(MaterialNames.WOOD, true, true, false, false), + new MaterialConfigOptions(MaterialNames.ENDER, true, true, true, true), + new MaterialConfigOptions(MaterialNames.QUARTZ, true, true, true, true), + new MaterialConfigOptions(MaterialNames.OBSIDIAN, true, true, true, true), + new MaterialConfigOptions(MaterialNames.LAPIS, true, true, false, false), + new MaterialConfigOptions(MaterialNames.PRISMARINE, true, true, true, true), + new MaterialConfigOptions(MaterialNames.REDSTONE, true, true, true, true), }; /** Reloads values saved through Forge's configuration screen. */ @@ -107,33 +107,37 @@ public void onConfigChange(final ConfigChangedEvent.OnConfigChangedEvent event) } } - /** Loads defaults, preserves legacy files, and latches the content mode once per launch. */ + /** Loads settings without changing the content mode of a running game. */ public static void init() { if (configuration == null) { configuration = new Configuration(new File(CONFIG_FILE)); MinecraftForge.EVENT_BUS.register(new BMeConfig()); } + populateConfiguration(configuration); + if (!contentModeLatched) { activeContentMode = configuredContentMode(configuration); contentModeLatched = true; } + if (configuration.hasChanged()) { configuration.save(); } } static void populateConfiguration(final Configuration target) { - // General settings are registered before the material-specific categories. Options.setEnableAchievements(target.getBoolean("achievements", GENERAL_CAT, true, - "If false, then Base Metals Achievements will be disabled (This is currently required if you disable any metals")); + "If false, Base Metals gameplay achievements will be disabled. Recipe-book unlocks are unaffected.")); + final Property achievements = target.getCategory(GENERAL_CAT).get("achievements"); final Property contentMode = target.get(GENERAL_CAT, CONTENT_MODE_PROPERTY, ContentMode.HIGH_FANTASY.serializedName(), "Controls Base Metals acquisition: high_fantasy keeps every historical recipe; " - + "low_fantasy restricts implausible forms; realism also removes mythical materials.", + + "low_fantasy restricts implausible forms.", ContentMode.serializedNames()); final String configuredValue = contentMode.getString(); + if (!ContentMode.isValidSerializedName(configuredValue)) { LOGGER.warn("Invalid Base Metals content mode '{}'; using '{}'.", configuredValue, ContentMode.HIGH_FANTASY.serializedName()); @@ -156,6 +160,7 @@ private static void configureGuiMetadata(final Configuration target, for (final String categoryName : GUI_CATEGORIES) { final String languageSuffix = categoryName.toLowerCase(java.util.Locale.ROOT) .replace(' ', '_'); + target.getCategory(categoryName) .setLanguageKey("config.basemetals.category." + languageSuffix) .setRequiresMcRestart(true); @@ -166,10 +171,13 @@ private static void configureGuiMetadata(final Configuration target, final String propertySuffix = WordUtils.capitalizeFully(identifier); final String materialLanguageKey = "config.basemetals.material." + identifier; final String category = options.getVanilla() ? VANILLA_CAT : MATERIALS_CAT; + decorate(target, category, "Enable" + propertySuffix, materialLanguageKey); + if (options.getHasFluid()) { decorate(target, FLUIDS_CAT, "Enabled " + propertySuffix, materialLanguageKey); } + if (options.getHasTraits()) { decorate(target, FORCED_TRAITS_CAT, "Force" + propertySuffix + "TraitRegistration", materialLanguageKey); @@ -180,10 +188,12 @@ private static void configureGuiMetadata(final Configuration target, private static void decorate(final Configuration target, final String category, final String propertyName, final String languageKey) { final Property property = target.getCategory(category).get(propertyName); + if (property == null) { throw new IllegalStateException("Missing Base Metals configuration property " + category + "/" + propertyName); } + property.setLanguageKey(languageKey).setRequiresMcRestart(true); } @@ -191,21 +201,25 @@ public static Configuration getConfiguration() { if (configuration == null) { throw new IllegalStateException("Base Metals configuration has not been initialized"); } + return configuration; } - /** Returns the mode latched during mod construction. */ + /** The mode chosen at startup, not a pending change in the config screen. */ public static ContentMode getActiveContentMode() { return activeContentMode; } - /** Reads the effective value of a configuration, treating an absent key as High Fantasy. */ + /** Old config files without a mode keep the High Fantasy default. */ public static ContentMode configuredContentMode(final Configuration target) { if (target == null || !target.hasCategory(GENERAL_CAT)) { return ContentMode.HIGH_FANTASY; } + final Property property = target.getCategory(GENERAL_CAT).get(CONTENT_MODE_PROPERTY); - return property == null ? ContentMode.HIGH_FANTASY + + return property == null + ? ContentMode.HIGH_FANTASY : ContentMode.fromSerializedName(property.getString()); } diff --git a/src/main/java/com/mcmoddev/basemetals/util/EventHandler.java b/src/main/java/com/mcmoddev/basemetals/util/EventHandler.java index e21fe1aa..36e417ca 100644 --- a/src/main/java/com/mcmoddev/basemetals/util/EventHandler.java +++ b/src/main/java/com/mcmoddev/basemetals/util/EventHandler.java @@ -37,7 +37,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; -@EventBusSubscriber(modid=BaseMetals.MODID) +@EventBusSubscriber(modid = BaseMetals.MODID) public final class EventHandler { public EventHandler() { @@ -47,25 +47,34 @@ public EventHandler() { @SubscribeEvent public static void attackEvent(final LivingAttackEvent event) { final float damage = event.getAmount(); + if (!(event.getEntityLiving() instanceof EntityPlayer)) { return; } + final EntityPlayer player = (EntityPlayer) event.getEntityLiving(); final ItemStack activeItemStack = player.getActiveItemStack(); + if (activeItemStack.isEmpty()) { return; } + if ((damage > 0.0F) && (activeItemStack.getItem() instanceof ItemMMDShield)) { final int i = 1 + MathHelper.floor(damage); + activeItemStack.damageItem(i, player); + if (activeItemStack.getCount() <= 0) { final EnumHand enumhand = player.getActiveHand(); + ForgeEventFactory.onPlayerDestroyItem(player, activeItemStack, enumhand); + if (enumhand == EnumHand.MAIN_HAND) { player.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, ItemStack.EMPTY); } else { player.setItemStackToSlot(EntityEquipmentSlot.OFFHAND, ItemStack.EMPTY); } + if (FMLCommonHandler.instance().getSide() == Side.CLIENT) { player.playSound(SoundEvents.BLOCK_ANVIL_BREAK, 0.8F, 0.8F + (player.world.rand.nextFloat() * 0.4F)); @@ -75,7 +84,8 @@ public static void attackEvent(final LivingAttackEvent event) { } /** Creates the two-slot crafting view used to evaluate shield upgrades at an anvil. */ - @Nonnull public static InventoryCrafting getDummyCraftingInv() { + @Nonnull + public static InventoryCrafting getDummyCraftingInv() { final Container tempContainer = new Container() { @Override @@ -99,9 +109,12 @@ public static void handleAnvilEvent(final AnvilUpdateEvent event) { } final InventoryCrafting recipeInput = getDummyCraftingInv(); + recipeInput.setInventorySlotContents(0, left); recipeInput.setInventorySlotContents(1, right); + final IRecipe recipe = CraftingManager.findMatchingRecipe(recipeInput, null); + if ((recipe instanceof ShieldUpgradeRecipe) && (((ShieldUpgradeRecipe) recipe).matches(recipeInput, null))) { event.setOutput(recipe.getCraftingResult(recipeInput)); @@ -112,11 +125,12 @@ public static void handleAnvilEvent(final AnvilUpdateEvent event) { @SubscribeEvent public static void mmdlibRegisterMaterials(final MMDLibRegisterMaterials event) { com.mcmoddev.basemetals.init.Materials.init(event); - if(FMLCommonHandler.instance().getEffectiveSide() == Side.CLIENT) { - com.mcmoddev.basemetals.init.Materials.initTooltips(); + + if (FMLCommonHandler.instance().getEffectiveSide() == Side.CLIENT) { + com.mcmoddev.basemetals.init.Materials.initTooltips(); } } - + @SubscribeEvent public static void mmdlibRegisterMaterialProperies(final MMDLibRegisterMaterialProperties event) { event.getRegistry().registerAll( @@ -130,5 +144,5 @@ public static void mmdlibRegisterMaterialProperies(final MMDLibRegisterMaterialP new ColdIronToolProperty().setRegistryName("basemetals:cold_as_ice"), new MithrilToolProperty().setRegistryName("basemetals:holy_roller"), new AquariumToolProperty().setRegistryName("basemetals:drown_bitca")); - } + } } diff --git a/src/main/java/com/mcmoddev/basemetals/util/VillagerTradeHelper.java b/src/main/java/com/mcmoddev/basemetals/util/VillagerTradeHelper.java index 1be733ad..eb02f7d6 100644 --- a/src/main/java/com/mcmoddev/basemetals/util/VillagerTradeHelper.java +++ b/src/main/java/com/mcmoddev/basemetals/util/VillagerTradeHelper.java @@ -12,42 +12,34 @@ public final class VillagerTradeHelper { private static final ResourceLocation[] professionList = { new ResourceLocation("minecraft:farmer"), new ResourceLocation("minecraft:librarian"), new ResourceLocation("minecraft:priest"), new ResourceLocation("minecraft:smith"), - new ResourceLocation("minecraft:butcher") }; + new ResourceLocation("minecraft:butcher")}; protected VillagerTradeHelper() { throw new IllegalAccessError("Not a instantiable class"); } /** - * Inserts trades by resolving the vanilla profession ID, then delegates to the - * resource-location overload. + * Adds trades to a vanilla profession by its numeric ID. * - * @param professionID - * Villager profession ID (0-4) - * @param careerID - * Villager career ID (1-3) - * @param tradeLevel - * Level of trade (1+) - * @param trades - * Trades to add to the given level + * @param professionID vanilla profession ID (0-4) + * @param careerID career ID within that profession (1-3) + * @param tradeLevel trade level, starting at 1 + * @param trades offers to add at that level */ public static void insertTrades(final int professionID, final int careerID, final int tradeLevel, final EntityVillager.ITradeList... trades) { final ResourceLocation profession = professionList[professionID]; + insertTrades(profession, careerID, tradeLevel, trades); } /** - * Inserts one or more trades to the default villager trade table. + * Adds trades to a vanilla profession by name. * - * @param professionName - * Villager profession - * @param careerID - * Villager career ID (1-3) - * @param tradeLevel - * Level of trade (1+) - * @param trades - * Trades to add to the given level + * @param professionName vanilla profession name + * @param careerID career ID within that profession (1-3) + * @param tradeLevel trade level, starting at 1 + * @param trades offers to add at that level */ public static void insertTrades(final String professionName, final int careerID, final int tradeLevel, final EntityVillager.ITradeList... trades) { @@ -55,22 +47,19 @@ public static void insertTrades(final String professionName, final int careerID, } /** - * Inserts one or more trades to the default villager trade table. + * Adds trades to a registered profession. * - * @param professionRL - * Villager profession - * @param careerID - * Villager career ID (1-3) - * @param tradeLevel - * Level of trade (1+) - * @param trades - * Trades to add to the given level + * @param professionRL profession registry name + * @param careerID career ID within that profession (1-3) + * @param tradeLevel trade level, starting at 1 + * @param trades offers to add at that level */ public static void insertTrades(final ResourceLocation professionRL, final int careerID, final int tradeLevel, final EntityVillager.ITradeList... trades) { final VillagerProfession profession = ForgeRegistries.VILLAGER_PROFESSIONS .getValue(professionRL); final VillagerCareer career = profession.getCareer(careerID); + career.addTrade(tradeLevel, trades); } } diff --git a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBitsRegistryEvents.java b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBitsRegistryEvents.java index 7f9afcd1..83634bca 100755 --- a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBitsRegistryEvents.java +++ b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBitsRegistryEvents.java @@ -24,64 +24,66 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -@Mod.EventBusSubscriber(modid=BaseMetals.MODID) +@Mod.EventBusSubscriber(modid = BaseMetals.MODID) public class VanillaBitsRegistryEvents { @SubscribeEvent public static void registerBlocks(RegistryEvent.Register ev) { Materials.getAllMaterials().stream() - .filter(MMDMaterial::isVanilla) - .forEach(mat -> mat.getBlocks().stream() - .filter(bl -> BaseMetals.MODID.equals(bl.getRegistryName().getNamespace())) - .forEach(bl -> ev.getRegistry().register(bl))); + .filter(MMDMaterial::isVanilla) + .forEach(mat -> mat.getBlocks().stream() + .filter(bl -> BaseMetals.MODID.equals(bl.getRegistryName().getNamespace())) + .forEach(bl -> ev.getRegistry().register(bl))); } - - @SubscribeEvent(priority=EventPriority.HIGHEST) + + @SubscribeEvent(priority = EventPriority.HIGHEST) public static void registerItems(RegistryEvent.Register ev) { Materials.getAllMaterials().stream() - .filter(mat -> mat.isVanilla()) - .forEach(mat -> mat.getItems().stream() - .map(it -> it.getItem()) - .filter(it -> BaseMetals.MODID.equals(it.getRegistryName().getNamespace())) - .forEach(it -> ev.getRegistry().register(it))); + .filter(mat -> mat.isVanilla()) + .forEach(mat -> mat.getItems().stream() + .map(it -> it.getItem()) + .filter(it -> BaseMetals.MODID.equals(it.getRegistryName().getNamespace())) + .forEach(it -> ev.getRegistry().register(it))); } - + @SideOnly(Side.CLIENT) @SubscribeEvent public static void modelRegistryBits(ModelRegistryEvent ev) { Arrays.asList(MaterialNames.CHARCOAL, MaterialNames.COAL, - MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.ENDER, + MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.ENDER, MaterialNames.GOLD, MaterialNames.IRON, MaterialNames.LAPIS, MaterialNames.OBSIDIAN, MaterialNames.PRISMARINE, MaterialNames.QUARTZ, - MaterialNames.WOOD, MaterialNames.REDSTONE, MaterialNames.STONE, + MaterialNames.WOOD, MaterialNames.REDSTONE, MaterialNames.STONE, MaterialNames.REDSTONE).stream() - .forEach(name -> { - if(!MaterialNames.PRISMARINE.equalsIgnoreCase(name)) { - Materials.getMaterialByName(name).getItems().stream() - .filter(item -> MMDLib.MODID.equalsIgnoreCase(item.getItem().getRegistryName().getNamespace())) - .filter(item -> !item.getItem().getRegistryName().getPath().equalsIgnoreCase(name)) - .forEach(item -> { - ModelLoader.setCustomModelResourceLocation(item.getItem(), 0, - new ModelResourceLocation(item.getItem().getRegistryName(), "inventory")); - }); - } + .forEach(name -> { + if (!MaterialNames.PRISMARINE.equalsIgnoreCase(name)) { + Materials.getMaterialByName(name).getItems().stream() + .filter(item -> MMDLib.MODID + .equalsIgnoreCase(item.getItem().getRegistryName().getNamespace())) + .filter(item -> !item.getItem().getRegistryName().getPath().equalsIgnoreCase(name)) + .forEach(item -> { + ModelLoader.setCustomModelResourceLocation(item.getItem(), 0, + new ModelResourceLocation(item.getItem().getRegistryName(), "inventory")); + }); + } - final Block block = Fluids.getFluidBlockByName(name); - if(block != null) { - final Item item = Item.getItemFromBlock(block); - final ResourceLocation resourceLocation = block.getRegistryName(); - final FluidStateMapper mapper = new FluidStateMapper( - resourceLocation.getNamespace() + ":" + name); + final Block block = Fluids.getFluidBlockByName(name); - if(BaseMetals.MODID.equalsIgnoreCase(item.getRegistryName().getNamespace())) { - if (item != null) { - ModelBakery.registerItemVariants(item); - ModelLoader.setCustomMeshDefinition(item, mapper); + if (block != null) { + final Item item = Item.getItemFromBlock(block); + final ResourceLocation resourceLocation = block.getRegistryName(); + final FluidStateMapper mapper = new FluidStateMapper( + resourceLocation.getNamespace() + ":" + name); + + if (BaseMetals.MODID.equalsIgnoreCase(item.getRegistryName().getNamespace())) { + if (item != null) { + ModelBakery.registerItemVariants(item); + ModelLoader.setCustomMeshDefinition(item, mapper); + } + + ModelLoader.setCustomStateMapper(block, mapper); + } } - ModelLoader.setCustomStateMapper(block, mapper); - } - } - }); + }); } - } diff --git a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBlocks.java b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBlocks.java index ff2ab325..24ee68c4 100755 --- a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBlocks.java +++ b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaBlocks.java @@ -16,16 +16,16 @@ import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -@Mod.EventBusSubscriber(modid=BaseMetals.MODID) +@Mod.EventBusSubscriber(modid = BaseMetals.MODID) public class VanillaBlocks extends Blocks { private VanillaBlocks() { throw new IllegalAccessError("Class cannot be instantiated!"); } - @SubscribeEvent(priority=EventPriority.HIGHEST) + @SubscribeEvent(priority = EventPriority.HIGHEST) public static void registerVanilla(MMDLibRegisterBlocks ev) { - // Reuse vanilla ore and storage blocks so integrations resolve one canonical form. + // Reuse vanilla blocks rather than register a second copy of each one. final MMDMaterial charcoal = Materials.getMaterialByName(MaterialNames.CHARCOAL); final MMDMaterial coal = Materials.getMaterialByName(MaterialNames.COAL); final MMDMaterial diamond = Materials.getMaterialByName(MaterialNames.DIAMOND); @@ -75,21 +75,22 @@ public static void registerVanilla(MMDLibRegisterBlocks ev) { create(Names.BLOCK, charcoal); } - Arrays.stream(new String[] {MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.GOLD, - MaterialNames.OBSIDIAN }) - .filter(n -> Options.isMaterialEnabled(n.toString())) - .filter(Materials::hasMaterial) - .map(Materials::getMaterialByName) - .forEach(mat -> { - Arrays.stream(new Names[] { Names.BARS, Names.DOOR, Names.TRAPDOOR, Names.BUTTON, Names.SLAB, Names.DOUBLE_SLAB, - Names.LEVER, Names.PRESSURE_PLATE, Names.STAIRS, Names.WALL }).forEach(n -> create(n, mat)); - }); + Arrays.stream(new String[]{MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.GOLD, + MaterialNames.OBSIDIAN}) + .filter(n -> Options.isMaterialEnabled(n.toString())) + .filter(Materials::hasMaterial) + .map(Materials::getMaterialByName) + .forEach(mat -> { + Arrays.stream(new Names[]{Names.BARS, Names.DOOR, Names.TRAPDOOR, Names.BUTTON, Names.SLAB, + Names.DOUBLE_SLAB, + Names.LEVER, Names.PRESSURE_PLATE, Names.STAIRS, Names.WALL}).forEach(n -> create(n, mat)); + }); if (Materials.hasMaterial(MaterialNames.GOLD) && Options.isMaterialEnabled(MaterialNames.GOLD)) { create(Names.PLATE, gold); } - - if (Materials.hasMaterial(MaterialNames.IRON) && Options.isMaterialEnabled(MaterialNames.IRON)) { + + if (Materials.hasMaterial(MaterialNames.IRON) && Options.isMaterialEnabled(MaterialNames.IRON)) { create(Names.PLATE, iron); create(Names.BUTTON, iron); diff --git a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaFluids.java b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaFluids.java index b12d210f..0f24ca3b 100755 --- a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaFluids.java +++ b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaFluids.java @@ -12,21 +12,21 @@ import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -@Mod.EventBusSubscriber(modid=BaseMetals.MODID) +@Mod.EventBusSubscriber(modid = BaseMetals.MODID) public class VanillaFluids extends Fluids { - @SubscribeEvent(priority=EventPriority.HIGHEST) + @SubscribeEvent(priority = EventPriority.HIGHEST) public static void registerFluids(MMDLibRegisterFluids ev) { // Integration mods may need these fluids even when Base Metals adds no matching equipment. Arrays.asList(MaterialNames.CHARCOAL, MaterialNames.COAL, - MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.ENDER, + MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.ENDER, MaterialNames.GOLD, MaterialNames.IRON, MaterialNames.LAPIS, MaterialNames.OBSIDIAN, MaterialNames.PRISMARINE, MaterialNames.QUARTZ, - MaterialNames.WOOD, MaterialNames.REDSTONE, MaterialNames.STONE, + MaterialNames.WOOD, MaterialNames.REDSTONE, MaterialNames.STONE, MaterialNames.REDSTONE).stream() - .filter(Options::isMaterialEnabled) - .filter(Options::isFluidEnabled).forEach(materialName -> { - addFluid(materialName, 2000, 10000, 769, 10); - addFluidBlock(materialName); - }); + .filter(Options::isMaterialEnabled) + .filter(Options::isFluidEnabled).forEach(materialName -> { + addFluid(materialName, 2000, 10000, 769, 10); + addFluidBlock(materialName); + }); } } diff --git a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaItems.java b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaItems.java index ffc2aa45..fe1bcc07 100755 --- a/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaItems.java +++ b/src/main/java/com/mcmoddev/basemetals/vanillabits/VanillaItems.java @@ -19,13 +19,13 @@ import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -@Mod.EventBusSubscriber(modid=BaseMetals.MODID) +@Mod.EventBusSubscriber(modid = BaseMetals.MODID) public class VanillaItems extends com.mcmoddev.lib.init.Items { private VanillaItems() { } - - @SubscribeEvent(priority=EventPriority.HIGHEST) + + @SubscribeEvent(priority = EventPriority.HIGHEST) public static void registerItemsEvent(MMDLibRegisterItems ev) { Materials.getMaterialByName(MaterialNames.CHARCOAL).addNewItemFromItemStack(Names.INGOT, new ItemStack(net.minecraft.init.Items.COAL, 1, 1)); @@ -47,88 +47,91 @@ public static void registerItemsEvent(MMDLibRegisterItems ev) { addStoneBits(); addWoodBits(); doSpecialMats(); - + // Emerald, obsidian, and quartz receive the vanilla-style tool and armor set. Arrays.asList(MaterialNames.EMERALD, MaterialNames.OBSIDIAN, MaterialNames.QUARTZ) - .stream().map(Materials::getMaterialByName) - .filter(mat -> Options.isMaterialEnabled(mat.toString())) - .forEach(material -> Arrays.asList(Names.AXE, Names.BOOTS, - Names.CHESTPLATE, Names.HELMET, Names.HOE, Names.LEGGINGS, Names.PICKAXE, Names.SHOVEL, Names.HORSE_ARMOR) - .stream() - .filter(n -> !material.hasItem(n)).forEach(n -> { - if (n == Names.HOE) { - Items.createHoe(material); - } else { - create(n, material); - } - })); - - // These solid vanilla materials support the shared equipment and building forms. - Arrays.asList(MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.GOLD, + .stream().map(Materials::getMaterialByName) + .filter(mat -> Options.isMaterialEnabled(mat.toString())) + .forEach(material -> Arrays.asList(Names.AXE, Names.BOOTS, + Names.CHESTPLATE, Names.HELMET, Names.HOE, Names.LEGGINGS, Names.PICKAXE, Names.SHOVEL, + Names.HORSE_ARMOR) + .stream() + .filter(n -> !material.hasItem(n)).forEach(n -> { + if (n == Names.HOE) { + Items.createHoe(material); + } else { + create(n, material); + } + })); + + // Add the equipment and building forms that vanilla does not provide. + Arrays.asList(MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.GOLD, MaterialNames.IRON, MaterialNames.OBSIDIAN, MaterialNames.QUARTZ) - .stream().map(Materials::getMaterialByName) - .filter(n -> Options.isMaterialEnabled(n.toString())) - .forEach(material -> Arrays.asList(Names.BOLT, Names.ARROW, Names.BOW, - Names.CROSSBOW, Names.FISHING_ROD, Names.ROD, Names.BARS, Names.SHEARS, Names.BUTTON, Names.SWORD, - Names.SHIELD, Names.DOOR, Names.SLAB) - .stream() - .filter(n -> !material.hasItem(n)).forEach(n -> { - if (n == Names.ARROW) { - Items.createArrow(material); - } else if (n == Names.BOLT) { - Items.createBolt(material); - } else if (n == Names.BOW) { - Items.createBow(material); - } else if (n == Names.CROSSBOW) { - Items.createCrossbow(material); - } else { - create(n, material); - } - })); - - // Crackhammers, gears, and scythes also make sense for stone and wood. - Arrays.asList(MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.GOLD, - MaterialNames.IRON, MaterialNames.OBSIDIAN, MaterialNames.QUARTZ, + .stream().map(Materials::getMaterialByName) + .filter(n -> Options.isMaterialEnabled(n.toString())) + .forEach(material -> Arrays.asList(Names.BOLT, Names.ARROW, Names.BOW, + Names.CROSSBOW, Names.FISHING_ROD, Names.ROD, Names.BARS, Names.SHEARS, Names.BUTTON, + Names.SWORD, + Names.SHIELD, Names.DOOR, Names.SLAB) + .stream() + .filter(n -> !material.hasItem(n)).forEach(n -> { + if (n == Names.ARROW) { + Items.createArrow(material); + } else if (n == Names.BOLT) { + Items.createBolt(material); + } else if (n == Names.BOW) { + Items.createBow(material); + } else if (n == Names.CROSSBOW) { + Items.createCrossbow(material); + } else { + create(n, material); + } + })); + + // Stone and wood also get crackhammers, gears, and scythes. + Arrays.asList(MaterialNames.DIAMOND, MaterialNames.EMERALD, MaterialNames.GOLD, + MaterialNames.IRON, MaterialNames.OBSIDIAN, MaterialNames.QUARTZ, MaterialNames.STONE, MaterialNames.WOOD) - .stream().map(Materials::getMaterialByName) - .filter(n -> Options.isMaterialEnabled(n.toString())) - .forEach(material -> Arrays.asList(Names.CRACKHAMMER, Names.GEAR, - Names.SCYTHE).stream() - .filter(n -> !material.hasItem(n)).forEach(n -> create(n, material))); - - // Powders and nuggets are available only where a meaningful source item exists. + .stream().map(Materials::getMaterialByName) + .filter(n -> Options.isMaterialEnabled(n.toString())) + .forEach(material -> Arrays.asList(Names.CRACKHAMMER, Names.GEAR, + Names.SCYTHE).stream() + .filter(n -> !material.hasItem(n)).forEach(n -> create(n, material))); + + // Add powders and nuggets for materials with a source item to crush. Arrays.asList(MaterialNames.COAL, MaterialNames.CHARCOAL, MaterialNames.DIAMOND, - MaterialNames.EMERALD, MaterialNames.GOLD, MaterialNames.IRON, - MaterialNames.OBSIDIAN, MaterialNames.REDSTONE, + MaterialNames.EMERALD, MaterialNames.GOLD, MaterialNames.IRON, + MaterialNames.OBSIDIAN, MaterialNames.REDSTONE, MaterialNames.QUARTZ).stream() - .map(Materials::getMaterialByName) - .filter(n -> Options.isMaterialEnabled(n.toString())) - .forEach(material -> - Arrays.asList(Names.SMALLPOWDER, Names.POWDER).stream() - .filter(n -> !material.hasItem(n)) - .forEach(n -> create(n, material))); + .map(Materials::getMaterialByName) + .filter(n -> Options.isMaterialEnabled(n.toString())) + .forEach(material -> Arrays.asList(Names.SMALLPOWDER, Names.POWDER).stream() + .filter(n -> !material.hasItem(n)) + .forEach(n -> create(n, material))); Arrays.asList(MaterialNames.COAL, MaterialNames.CHARCOAL, MaterialNames.DIAMOND, - MaterialNames.EMERALD, MaterialNames.GOLD, MaterialNames.IRON, + MaterialNames.EMERALD, MaterialNames.GOLD, MaterialNames.IRON, MaterialNames.OBSIDIAN, MaterialNames.QUARTZ).stream() - .filter(Options::isMaterialEnabled) - .map(Materials::getMaterialByName) - .filter(m -> !m.hasItem(Names.NUGGET)).forEach(material -> create(Names.NUGGET, material)); - - // These one-off forms do not share a useful material group. - if(Options.isMaterialEnabled(MaterialNames.STONE)) { + .filter(Options::isMaterialEnabled) + .map(Materials::getMaterialByName) + .filter(m -> !m.hasItem(Names.NUGGET)).forEach(material -> create(Names.NUGGET, material)); + + if (Options.isMaterialEnabled(MaterialNames.STONE)) { create(Names.ROD, Materials.getMaterialByName(MaterialNames.STONE)); } - if(Options.isMaterialEnabled(MaterialNames.LAPIS)) { + + if (Options.isMaterialEnabled(MaterialNames.LAPIS)) { create(Names.SMALLPOWDER, Materials.getMaterialByName(MaterialNames.LAPIS)); } - if(Options.isMaterialEnabled(MaterialNames.OBSIDIAN)) { + + if (Options.isMaterialEnabled(MaterialNames.OBSIDIAN)) { create(Names.INGOT, Materials.getMaterialByName(MaterialNames.OBSIDIAN)); } - if(Options.isMaterialEnabled(MaterialNames.REDSTONE)) { + + if (Options.isMaterialEnabled(MaterialNames.REDSTONE)) { create(Names.INGOT, Materials.getMaterialByName(MaterialNames.REDSTONE)); } } - + private static void setBurnTimes(@Nonnull final MMDMaterial material) { if (material.hasItem(Names.NUGGET)) { ((IMMDBurnableObject) material.getItem(Names.NUGGET)).setBurnTime(NUGGET_BURN_TIME); @@ -147,9 +150,9 @@ private static void setBurnTimes(@Nonnull final MMDMaterial material) { ((IMMDBurnableObject) material.getItem("ItemBlock_charcoal_block")).setBurnTime(BLOCK_BURN_TIME); } } - + private static void doSpecialMats() { - if (Materials.hasMaterial(MaterialNames.CHARCOAL) && + if (Materials.hasMaterial(MaterialNames.CHARCOAL) && Options.isMaterialEnabled(MaterialNames.CHARCOAL)) { final MMDMaterial charcoal = Materials.getMaterialByName(MaterialNames.CHARCOAL); @@ -160,7 +163,7 @@ private static void doSpecialMats() { setBurnTimes(charcoal); } - if (Materials.hasMaterial(MaterialNames.COAL) && + if (Materials.hasMaterial(MaterialNames.COAL) && Options.isMaterialEnabled(MaterialNames.COAL)) { final MMDMaterial coal = Materials.getMaterialByName(MaterialNames.COAL); @@ -171,7 +174,7 @@ private static void doSpecialMats() { setBurnTimes(coal); } - if (Materials.hasMaterial(MaterialNames.REDSTONE) && + if (Materials.hasMaterial(MaterialNames.REDSTONE) && Options.isMaterialEnabled(MaterialNames.REDSTONE)) { final MMDMaterial redstone = Materials.getMaterialByName(MaterialNames.REDSTONE); @@ -179,13 +182,12 @@ private static void doSpecialMats() { create(Names.SMALLPOWDER, redstone); } - if (Materials.hasMaterial(MaterialNames.LAPIS) && + if (Materials.hasMaterial(MaterialNames.LAPIS) && Options.isMaterialEnabled(MaterialNames.LAPIS)) { create(Names.SMALLPOWDER, Materials.getMaterialByName(MaterialNames.LAPIS)); } } - private static void addDiamondBits() { final MMDMaterial diamond = Materials.getMaterialByName(MaterialNames.DIAMOND); diff --git a/src/main/java/com/mcmoddev/basemetals/worldgen/BaseMetalsWorldgenProvider.java b/src/main/java/com/mcmoddev/basemetals/worldgen/BaseMetalsWorldgenProvider.java index 6d81c21a..67770cf1 100644 --- a/src/main/java/com/mcmoddev/basemetals/worldgen/BaseMetalsWorldgenProvider.java +++ b/src/main/java/com/mcmoddev/basemetals/worldgen/BaseMetalsWorldgenProvider.java @@ -1,7 +1,6 @@ package com.mcmoddev.basemetals.worldgen; import com.mcmoddev.basemetals.BaseMetals; -import com.mcmoddev.basemetals.content.ContentPolicy; import com.mcmoddev.basemetals.data.MaterialNames; import net.minecraft.util.ResourceLocation; import zone.moddev.mc.orespawn.api.OreDimensionSelector; @@ -10,7 +9,7 @@ import zone.moddev.mc.orespawn.api.OreSpawnApi; import zone.moddev.mc.orespawn.api.WorldgenProvider; -/** Builds Base Metals' OreSpawn defaults from the startup-latched content mode. */ +/** Supplies Base Metals' eleven ore rules; content modes do not change worldgen. */ public final class BaseMetalsWorldgenProvider { public static final int PROVIDER_REVISION = 2; private static final ResourceLocation NETHER = id("minecraft", "the_nether"); @@ -23,34 +22,36 @@ private BaseMetalsWorldgenProvider() { } public static boolean enqueue() { - return OreSpawnApi.enqueue(build(ContentPolicy.active())); + return OreSpawnApi.enqueue(build()); } - public static WorldgenProvider build(final ContentPolicy policy) { + public static WorldgenProvider build() { final WorldgenProvider.Builder provider = WorldgenProvider .builder(BaseMetals.MODID, PROVIDER_REVISION) .mergeNewEntriesIntoExistingWorlds(true); - addDimensionOre(provider, policy, MaterialNames.COLDIRON, NETHER, 0, 127, 5.0D); - addDimensionOre(provider, policy, MaterialNames.ADAMANTINE, NETHER, 0, 127, 2.0D); - addDimensionOre(provider, policy, MaterialNames.STARSTEEL, END, 0, 254, 5.0D); - addOrdinaryOre(provider, policy, MaterialNames.COPPER, 0, 95, 10.0D); - addOrdinaryOre(provider, policy, MaterialNames.SILVER, 0, 31, 4.0D); - addOrdinaryOre(provider, policy, MaterialNames.TIN, 0, 127, 10.0D); - addOrdinaryOre(provider, policy, MaterialNames.LEAD, 0, 63, 5.0D); - addOrdinaryOre(provider, policy, MaterialNames.ZINC, 0, 95, 5.0D); - addOrdinaryOre(provider, policy, MaterialNames.MERCURY, 0, 31, 3.0D); - addOrdinaryOre(provider, policy, MaterialNames.NICKEL, 32, 95, 1.0D); - addOrdinaryOre(provider, policy, MaterialNames.PLATINUM, 1, 31, 0.125D); + addDimensionOre(provider, MaterialNames.COLDIRON, NETHER, 0, 127, 5.0D); + addDimensionOre(provider, MaterialNames.ADAMANTINE, NETHER, 0, 127, 2.0D); + addDimensionOre(provider, MaterialNames.STARSTEEL, END, 0, 254, 5.0D); + addOrdinaryOre(provider, MaterialNames.COPPER, 0, 95, 10.0D); + addOrdinaryOre(provider, MaterialNames.SILVER, 0, 31, 4.0D); + addOrdinaryOre(provider, MaterialNames.TIN, 0, 127, 10.0D); + addOrdinaryOre(provider, MaterialNames.LEAD, 0, 63, 5.0D); + addOrdinaryOre(provider, MaterialNames.ZINC, 0, 95, 5.0D); + addOrdinaryOre(provider, MaterialNames.MERCURY, 0, 31, 3.0D); + addOrdinaryOre(provider, MaterialNames.NICKEL, 32, 95, 1.0D); + addOrdinaryOre(provider, MaterialNames.PLATINUM, 1, 31, 0.125D); + return provider.build(); } private static void addDimensionOre(final WorldgenProvider.Builder provider, - final ContentPolicy policy, final String material, final ResourceLocation dimension, + final String material, final ResourceLocation dimension, final int minY, final int maxY, final double attempts) { final ResourceLocation block = id(BaseMetals.MODID, material + "_ore"); + provider.ore(id(BaseMetals.MODID, "legacy/" + material + "_ore"), block, ore -> ore - .enabled(policy.defaultsOreEnabled(material)) + .enabled(true) .nativeGeneration(false) .retrogen(false) .output(block, 100.0D) @@ -58,11 +59,12 @@ private static void addDimensionOre(final WorldgenProvider.Builder provider, } private static void addOrdinaryOre(final WorldgenProvider.Builder provider, - final ContentPolicy policy, final String material, final int minY, + final String material, final int minY, final int maxY, final double attempts) { final ResourceLocation block = id(BaseMetals.MODID, material + "_ore"); + provider.ore(id(BaseMetals.MODID, "legacy/" + material + "_ore"), block, ore -> ore - .enabled(policy.defaultsOreEnabled(material)) + .enabled(true) .nativeGeneration(false) .retrogen(false) .output(block, 100.0D) diff --git a/src/main/resources/assets/basemetals/advancements/_factories.json b/src/main/resources/assets/basemetals/advancements/_factories.json new file mode 100644 index 00000000..0eed28f4 --- /dev/null +++ b/src/main/resources/assets/basemetals/advancements/_factories.json @@ -0,0 +1,8 @@ +{ + "conditions": { + "achievement": "com.mcmoddev.basemetals.advancement.AchievementCondition", + "enabled": "com.mcmoddev.lib.recipe.conditions.ConditionEnabled", + "hammer": "com.mcmoddev.lib.recipe.conditions.HammerEnabled", + "plate": "com.mcmoddev.lib.recipe.conditions.PlateRepairEnabled" + } +} diff --git a/src/main/resources/assets/basemetals/lang/de_de.lang b/src/main/resources/assets/basemetals/lang/de_de.lang index eb6ace7f..7d406d3f 100644 --- a/src/main/resources/assets/basemetals/lang/de_de.lang +++ b/src/main/resources/assets/basemetals/lang/de_de.lang @@ -1,3 +1,6 @@ +achievement.pewter_maker=Hartzinn +achievement.pewter_maker.desc=Kombiniere Zinn-, Kupfer- und Bleipulver, um Hartzinn herzustellen. + basemetals.crackhammer=Zerkleinerte Blöcke / Gegenstände #Creative Tabs @@ -1831,13 +1834,11 @@ config.basemetals.category.forced_traits=Erzwungene Eigenschaften config.basemetals.category.forced_traits.tooltip=Die Registrierung von MMDLib-Eigenschaften für Base-Metals-Materialien erzwingen. config.basemetals.option.achievements=Erfolge config.basemetals.option.content_mode=Inhaltsmodus -config.basemetals.option.content_mode.tooltip=High Fantasy, Low Fantasy oder Realismus wählen. Die ausgewählte Richtlinie wird nach einem Neustart von Minecraft wirksam. +config.basemetals.option.content_mode.tooltip=High Fantasy oder Low Fantasy wählen. Die ausgewählte Richtlinie wird nach einem Neustart von Minecraft wirksam. config.basemetals.content_mode.high_fantasy=High Fantasy config.basemetals.content_mode.low_fantasy=Low Fantasy -config.basemetals.content_mode.realism=Realismus config.basemetals.warning.content_mode.title=Inhaltsmodus von Base Metals ändern? config.basemetals.warning.content_mode.message=Von %s zu %s wechseln? Rezepte, Handel, Beute und Integrationen ändern sich nach dem Neustart. -config.basemetals.warning.content_mode.realism=Von %s zu %s wechseln? Bestehende OreSpawn-Weltprofile bleiben erhalten; Regeln für Adamant, Kalteisen und Sternenstahl müssen bei Bedarf manuell deaktiviert werden. config.basemetals.warning.confirm=Speichern und später neu starten config.basemetals.warning.disable_ores.title=Aktion für OreSpawn-Regeln erforderlich config.basemetals.warning.disable_ores.message=Vor dem Neustart müssen diese Regeln in OreSpawn deaktiviert werden, da fehlende Ausgabeblöcke sonst den Anbieter ungültig machen: %s @@ -1880,4 +1881,3 @@ config.basemetals.material.prismarine=Prismarin config.basemetals.material.redstone=Redstone config.basemetals.content_mode.high_fantasy.description=Alle historischen Inhalte und Beschaffungswege von Base Metals bleiben verfügbar. config.basemetals.content_mode.low_fantasy.description=Fantasymaterialien bleiben erhalten, aber unplausible Ausrüstungs- und Baurezepte werden ausgeblendet. -config.basemetals.content_mode.realism.description=Die Low-Fantasy-Beschränkungen gelten, und der normale Erwerb mythischer Materialien ist deaktiviert. diff --git a/src/main/resources/assets/basemetals/lang/en_au.lang b/src/main/resources/assets/basemetals/lang/en_au.lang index fc22a2cd..3008e80c 100644 --- a/src/main/resources/assets/basemetals/lang/en_au.lang +++ b/src/main/resources/assets/basemetals/lang/en_au.lang @@ -1,3 +1,7 @@ +achievement.cupronickel_maker=Cupronickel +achievement.pewter_maker=Pewter +achievement.pewter_maker.desc=Combine powdered tin, copper and lead to make pewter + itemGroup.basemetals.blocks=Base Metals Blocks itemGroup.basemetals.combat=Base Metals Combat itemGroup.basemetals.items=Base Metals Items @@ -587,13 +591,11 @@ config.basemetals.category.forced_traits=Forced Traits config.basemetals.category.forced_traits.tooltip=Force MMDLib trait registration for Base Metals materials. config.basemetals.option.achievements=Achievements config.basemetals.option.content_mode=Content Mode -config.basemetals.option.content_mode.tooltip=Choose High Fantasy, Low Fantasy, or Realism. The selected policy takes effect after restarting Minecraft. +config.basemetals.option.content_mode.tooltip=Choose High Fantasy or Low Fantasy. The selected policy takes effect after restarting Minecraft. config.basemetals.content_mode.high_fantasy=High Fantasy config.basemetals.content_mode.low_fantasy=Low Fantasy -config.basemetals.content_mode.realism=Realism config.basemetals.warning.content_mode.title=Change Base Metals content mode? config.basemetals.warning.content_mode.message=Change from %s to %s? Recipes, trades, loot and integrations will change after restart. -config.basemetals.warning.content_mode.realism=Change from %s to %s? Existing OreSpawn world profiles are preserved; disable Adamantine, Cold Iron and Starsteel rules manually where required. config.basemetals.warning.confirm=Save and restart later config.basemetals.warning.disable_ores.title=OreSpawn rule action required config.basemetals.warning.disable_ores.message=Before restarting, disable these rules in OreSpawn or their missing output blocks will invalidate the provider: %s @@ -636,4 +638,3 @@ config.basemetals.material.prismarine=Prismarine config.basemetals.material.redstone=Redstone config.basemetals.content_mode.high_fantasy.description=All historical Base Metals content and acquisition routes remain available. config.basemetals.content_mode.low_fantasy.description=Fantasy materials remain, but implausible equipment and construction recipes are hidden. -config.basemetals.content_mode.realism.description=Low Fantasy restrictions apply and normal acquisition of mythical materials is disabled. diff --git a/src/main/resources/assets/basemetals/lang/en_ca.lang b/src/main/resources/assets/basemetals/lang/en_ca.lang index 21142cce..d7a2a041 100644 --- a/src/main/resources/assets/basemetals/lang/en_ca.lang +++ b/src/main/resources/assets/basemetals/lang/en_ca.lang @@ -1,3 +1,7 @@ +achievement.cupronickel_maker=Cupronickel +achievement.pewter_maker=Pewter +achievement.pewter_maker.desc=Combine powdered tin, copper and lead to make pewter + itemGroup.basemetals.blocks=Base Metals Blocks itemGroup.basemetals.combat=Base Metals Combat itemGroup.basemetals.items=Base Metals Items @@ -589,13 +593,11 @@ config.basemetals.category.forced_traits=Forced Traits config.basemetals.category.forced_traits.tooltip=Force MMDLib trait registration for Base Metals materials. config.basemetals.option.achievements=Achievements config.basemetals.option.content_mode=Content Mode -config.basemetals.option.content_mode.tooltip=Choose High Fantasy, Low Fantasy, or Realism. The selected policy takes effect after restarting Minecraft. +config.basemetals.option.content_mode.tooltip=Choose High Fantasy or Low Fantasy. The selected policy takes effect after restarting Minecraft. config.basemetals.content_mode.high_fantasy=High Fantasy config.basemetals.content_mode.low_fantasy=Low Fantasy -config.basemetals.content_mode.realism=Realism config.basemetals.warning.content_mode.title=Change Base Metals content mode? config.basemetals.warning.content_mode.message=Change from %s to %s? Recipes, trades, loot and integrations will change after restart. -config.basemetals.warning.content_mode.realism=Change from %s to %s? Existing OreSpawn world profiles are preserved; disable Adamantine, Cold Iron and Starsteel rules manually where required. config.basemetals.warning.confirm=Save and restart later config.basemetals.warning.disable_ores.title=OreSpawn rule action required config.basemetals.warning.disable_ores.message=Before restarting, disable these rules in OreSpawn or their missing output blocks will invalidate the provider: %s @@ -638,4 +640,3 @@ config.basemetals.material.prismarine=Prismarine config.basemetals.material.redstone=Redstone config.basemetals.content_mode.high_fantasy.description=All historical Base Metals content and acquisition routes remain available. config.basemetals.content_mode.low_fantasy.description=Fantasy materials remain, but implausible equipment and construction recipes are hidden. -config.basemetals.content_mode.realism.description=Low Fantasy restrictions apply and normal acquisition of mythical materials is disabled. diff --git a/src/main/resources/assets/basemetals/lang/en_en.lang b/src/main/resources/assets/basemetals/lang/en_en.lang index fdd53bcc..37bf4ca5 100644 --- a/src/main/resources/assets/basemetals/lang/en_en.lang +++ b/src/main/resources/assets/basemetals/lang/en_en.lang @@ -1,3 +1,7 @@ +achievement.cupronickel_maker=Cupronickel +achievement.pewter_maker=Pewter +achievement.pewter_maker.desc=Combine powdered tin, copper and lead to make pewter + itemGroup.basemetals.blocks=Base Metals Blocks itemGroup.basemetals.combat=Base Metals Combat itemGroup.basemetals.items=Base Metals Items @@ -588,13 +592,11 @@ config.basemetals.category.forced_traits=Forced Traits config.basemetals.category.forced_traits.tooltip=Force MMDLib trait registration for Base Metals materials. config.basemetals.option.achievements=Achievements config.basemetals.option.content_mode=Content Mode -config.basemetals.option.content_mode.tooltip=Choose High Fantasy, Low Fantasy, or Realism. The selected policy takes effect after restarting Minecraft. +config.basemetals.option.content_mode.tooltip=Choose High Fantasy or Low Fantasy. The selected policy takes effect after restarting Minecraft. config.basemetals.content_mode.high_fantasy=High Fantasy config.basemetals.content_mode.low_fantasy=Low Fantasy -config.basemetals.content_mode.realism=Realism config.basemetals.warning.content_mode.title=Change Base Metals content mode? config.basemetals.warning.content_mode.message=Change from %s to %s? Recipes, trades, loot and integrations will change after restart. -config.basemetals.warning.content_mode.realism=Change from %s to %s? Existing OreSpawn world profiles are preserved; disable Adamantine, Cold Iron and Starsteel rules manually where required. config.basemetals.warning.confirm=Save and restart later config.basemetals.warning.disable_ores.title=OreSpawn rule action required config.basemetals.warning.disable_ores.message=Before restarting, disable these rules in OreSpawn or their missing output blocks will invalidate the provider: %s @@ -637,4 +639,3 @@ config.basemetals.material.prismarine=Prismarine config.basemetals.material.redstone=Redstone config.basemetals.content_mode.high_fantasy.description=All historical Base Metals content and acquisition routes remain available. config.basemetals.content_mode.low_fantasy.description=Fantasy materials remain, but implausible equipment and construction recipes are hidden. -config.basemetals.content_mode.realism.description=Low Fantasy restrictions apply and normal acquisition of mythical materials is disabled. diff --git a/src/main/resources/assets/basemetals/lang/en_gb.lang b/src/main/resources/assets/basemetals/lang/en_gb.lang index 88d79f61..b65342bb 100644 --- a/src/main/resources/assets/basemetals/lang/en_gb.lang +++ b/src/main/resources/assets/basemetals/lang/en_gb.lang @@ -1,3 +1,7 @@ +achievement.cupronickel_maker=Cupronickel +achievement.pewter_maker=Pewter +achievement.pewter_maker.desc=Combine powdered tin, copper and lead to make pewter + itemGroup.basemetals.blocks=Base Metals Blocks itemGroup.basemetals.combat=Base Metals Combat itemGroup.basemetals.items=Base Metals Items @@ -589,13 +593,11 @@ config.basemetals.category.forced_traits=Forced Traits config.basemetals.category.forced_traits.tooltip=Force MMDLib trait registration for Base Metals materials. config.basemetals.option.achievements=Achievements config.basemetals.option.content_mode=Content Mode -config.basemetals.option.content_mode.tooltip=Choose High Fantasy, Low Fantasy, or Realism. The selected policy takes effect after restarting Minecraft. +config.basemetals.option.content_mode.tooltip=Choose High Fantasy or Low Fantasy. The selected policy takes effect after restarting Minecraft. config.basemetals.content_mode.high_fantasy=High Fantasy config.basemetals.content_mode.low_fantasy=Low Fantasy -config.basemetals.content_mode.realism=Realism config.basemetals.warning.content_mode.title=Change Base Metals content mode? config.basemetals.warning.content_mode.message=Change from %s to %s? Recipes, trades, loot and integrations will change after restart. -config.basemetals.warning.content_mode.realism=Change from %s to %s? Existing OreSpawn world profiles are preserved; disable Adamantine, Cold Iron and Starsteel rules manually where required. config.basemetals.warning.confirm=Save and restart later config.basemetals.warning.disable_ores.title=OreSpawn rule action required config.basemetals.warning.disable_ores.message=Before restarting, disable these rules in OreSpawn or their missing output blocks will invalidate the provider: %s @@ -638,4 +640,3 @@ config.basemetals.material.prismarine=Prismarine config.basemetals.material.redstone=Redstone config.basemetals.content_mode.high_fantasy.description=All historical Base Metals content and acquisition routes remain available. config.basemetals.content_mode.low_fantasy.description=Fantasy materials remain, but implausible equipment and construction recipes are hidden. -config.basemetals.content_mode.realism.description=Low Fantasy restrictions apply and normal acquisition of mythical materials is disabled. diff --git a/src/main/resources/assets/basemetals/lang/en_pt.lang b/src/main/resources/assets/basemetals/lang/en_pt.lang index 8d95b987..b76c4fb3 100644 --- a/src/main/resources/assets/basemetals/lang/en_pt.lang +++ b/src/main/resources/assets/basemetals/lang/en_pt.lang @@ -1,3 +1,7 @@ +achievement.cupronickel_maker=Cupronickel +achievement.pewter_maker=Pewter +achievement.pewter_maker.desc=Combine powdered tin, copper and lead to make pewter + itemGroup.basemetals.blocks=Base Metals Blocks itemGroup.basemetals.combat=Base Metals Combat itemGroup.basemetals.items=Base Metals Items @@ -545,13 +549,11 @@ config.basemetals.category.forced_traits=Forced Traits config.basemetals.category.forced_traits.tooltip=Make MMDLib register traits for Base Metals materials, no questions asked. config.basemetals.option.achievements=Feats config.basemetals.option.content_mode=Content Course -config.basemetals.option.content_mode.tooltip=Choose High Fantasy, Low Fantasy, or Realism. Yer chosen course takes hold after restarting Minecraft. +config.basemetals.option.content_mode.tooltip=Choose High Fantasy or Low Fantasy. Yer chosen course takes hold after restarting Minecraft. config.basemetals.content_mode.high_fantasy=High Fantasy config.basemetals.content_mode.low_fantasy=Low Fantasy -config.basemetals.content_mode.realism=Realism config.basemetals.warning.content_mode.title=Change Base Metals' content course? config.basemetals.warning.content_mode.message=Sail from %s to %s? Recipes, trades, loot, and integrations change after restart. -config.basemetals.warning.content_mode.realism=Sail from %s to %s? Existing OreSpawn world charts stay untouched; disable Unbreakable, Devil-Iron, and Star-Steel rules by hand where needed. config.basemetals.warning.confirm=Save and restart later config.basemetals.warning.disable_ores.title=OreSpawn orders required config.basemetals.warning.disable_ores.message=Before restarting, disable these OreSpawn rules or missing output blocks will scuttle the provider: %s @@ -594,4 +596,3 @@ config.basemetals.material.prismarine=Prismarine config.basemetals.material.redstone=Redstone config.basemetals.content_mode.high_fantasy.description=All the old Base Metals cargo and ways to claim it remain aboard. config.basemetals.content_mode.low_fantasy.description=Fantasy materials remain, but daft equipment and building recipes walk the plank. -config.basemetals.content_mode.realism.description=Low Fantasy limits apply, and mythical materials cannot be gained by ordinary means. diff --git a/src/main/resources/assets/basemetals/lang/en_us.lang b/src/main/resources/assets/basemetals/lang/en_us.lang index a36ef194..8e7347f5 100644 --- a/src/main/resources/assets/basemetals/lang/en_us.lang +++ b/src/main/resources/assets/basemetals/lang/en_us.lang @@ -61,7 +61,7 @@ achievement.invar_maker.desc=Combine powdered iron and nickel to make invar achievement.juggernaut.desc=Wear a full suit of adamantine armor achievement.metallurgy.desc=Craft any alloy blend achievement.mithril_maker.desc=Combine powdered silver, cold-iron and mercury to make mithril -achievement.pewter_maker.desc=Combine powdered ??? and ??? to make pewter +achievement.pewter_maker.desc=Combine powdered tin, copper and lead to make pewter achievement.moon_boots.desc=Wear a pair of star-steel boots achievement.scuba_diver.desc=Wear a full suit of aquarium armor and swim under water achievement.steel_maker.desc=Combine powdered iron and powdered charcoal to make steel @@ -1925,13 +1925,11 @@ config.basemetals.category.forced_traits=Forced Traits config.basemetals.category.forced_traits.tooltip=Force MMDLib trait registration for Base Metals materials. config.basemetals.option.achievements=Achievements config.basemetals.option.content_mode=Content Mode -config.basemetals.option.content_mode.tooltip=Choose High Fantasy, Low Fantasy, or Realism. The selected policy takes effect after restarting Minecraft. +config.basemetals.option.content_mode.tooltip=Choose High Fantasy or Low Fantasy. The selected policy takes effect after restarting Minecraft. config.basemetals.content_mode.high_fantasy=High Fantasy config.basemetals.content_mode.low_fantasy=Low Fantasy -config.basemetals.content_mode.realism=Realism config.basemetals.warning.content_mode.title=Change Base Metals content mode? config.basemetals.warning.content_mode.message=Change from %s to %s? Recipes, trades, loot and integrations will change after restart. -config.basemetals.warning.content_mode.realism=Change from %s to %s? Existing OreSpawn world profiles are preserved; disable Adamantine, Cold Iron and Starsteel rules manually where required. config.basemetals.warning.confirm=Save and restart later config.basemetals.warning.disable_ores.title=OreSpawn rule action required config.basemetals.warning.disable_ores.message=Before restarting, disable these rules in OreSpawn or their missing output blocks will invalidate the provider: %s @@ -1974,4 +1972,3 @@ config.basemetals.material.prismarine=Prismarine config.basemetals.material.redstone=Redstone config.basemetals.content_mode.high_fantasy.description=All historical Base Metals content and acquisition routes remain available. config.basemetals.content_mode.low_fantasy.description=Fantasy materials remain, but implausible equipment and construction recipes are hidden. -config.basemetals.content_mode.realism.description=Low Fantasy restrictions apply and normal acquisition of mythical materials is disabled. diff --git a/src/main/resources/assets/basemetals/lang/es_es.lang b/src/main/resources/assets/basemetals/lang/es_es.lang index 142c01ab..6c8b9bbb 100644 --- a/src/main/resources/assets/basemetals/lang/es_es.lang +++ b/src/main/resources/assets/basemetals/lang/es_es.lang @@ -1,3 +1,7 @@ +achievement.cupronickel_maker=Cuproníquel +achievement.pewter_maker=Peltre +achievement.pewter_maker.desc=Combina polvo de estaño, cobre y plomo para fabricar peltre. + language_support_goals=english (en_US,en_EN,en_CA,en_GB, en_AU, en_PT), italian(IT_it), spanish (es_MX,es_ES), simplified chinese (zh_CN), japanese (ja_JA), portugese (pt_BR), german (de_DE) itemGroup.basemetals.blocks=Base Metals Blocks @@ -544,13 +548,11 @@ config.basemetals.category.forced_traits=Rasgos forzados config.basemetals.category.forced_traits.tooltip=Fuerza el registro de rasgos de MMDLib para los materiales de Base Metals. config.basemetals.option.achievements=Logros config.basemetals.option.content_mode=Modo de contenido -config.basemetals.option.content_mode.tooltip=Elige Alta fantasía, Baja fantasía o Realismo. La política seleccionada se aplica después de reiniciar Minecraft. +config.basemetals.option.content_mode.tooltip=Elige Alta fantasía o Baja fantasía. La política seleccionada se aplica después de reiniciar Minecraft. config.basemetals.content_mode.high_fantasy=Alta fantasía config.basemetals.content_mode.low_fantasy=Baja fantasía -config.basemetals.content_mode.realism=Realismo config.basemetals.warning.content_mode.title=¿Cambiar el modo de contenido de Base Metals? config.basemetals.warning.content_mode.message=¿Cambiar de %s a %s? Las recetas, los intercambios, el botín y las integraciones cambiarán después de reiniciar. -config.basemetals.warning.content_mode.realism=¿Cambiar de %s a %s? Los perfiles de mundo existentes de OreSpawn se conservarán; desactiva manualmente las reglas de adamantina, glacierro y estrellacero cuando sea necesario. config.basemetals.warning.confirm=Guardar y reiniciar más tarde config.basemetals.warning.disable_ores.title=Se requiere una acción en las reglas de OreSpawn config.basemetals.warning.disable_ores.message=Antes de reiniciar, desactiva estas reglas en OreSpawn o la falta de sus bloques de salida invalidará el proveedor: %s @@ -593,4 +595,3 @@ config.basemetals.material.prismarine=Prismarina config.basemetals.material.redstone=Redstone config.basemetals.content_mode.high_fantasy.description=Todo el contenido histórico y las vías de obtención de Base Metals siguen disponibles. config.basemetals.content_mode.low_fantasy.description=Los materiales fantásticos permanecen, pero se ocultan las recetas de equipo y construcción poco plausibles. -config.basemetals.content_mode.realism.description=Se aplican las restricciones de Baja fantasía y se desactiva la obtención normal de materiales míticos. diff --git a/src/main/resources/assets/basemetals/lang/es_mx.lang b/src/main/resources/assets/basemetals/lang/es_mx.lang index ab9a58d9..f2e0febf 100644 --- a/src/main/resources/assets/basemetals/lang/es_mx.lang +++ b/src/main/resources/assets/basemetals/lang/es_mx.lang @@ -1,3 +1,7 @@ +achievement.cupronickel_maker=Cuproníquel +achievement.pewter_maker=Peltre +achievement.pewter_maker.desc=Combina polvo de estaño, cobre y plomo para fabricar peltre. + language_support_goals=english (en_US,en_EN,en_CA,en_GB, en_AU, en_PT), italian(IT_it), spanish (es_MX,es_ES), simplified chinese (zh_CN), japanese (ja_JA), portugese (pt_BR), german (de_DE) itemGroup.basemetals.blocks=Base Metals Blocks @@ -545,13 +549,11 @@ config.basemetals.category.forced_traits=Rasgos forzados config.basemetals.category.forced_traits.tooltip=Fuerza el registro de rasgos de MMDLib para los materiales de Base Metals. config.basemetals.option.achievements=Logros config.basemetals.option.content_mode=Modo de contenido -config.basemetals.option.content_mode.tooltip=Elige Alta fantasía, Baja fantasía o Realismo. La política seleccionada se aplica después de reiniciar Minecraft. +config.basemetals.option.content_mode.tooltip=Elige Alta fantasía o Baja fantasía. La política seleccionada se aplica después de reiniciar Minecraft. config.basemetals.content_mode.high_fantasy=Alta fantasía config.basemetals.content_mode.low_fantasy=Baja fantasía -config.basemetals.content_mode.realism=Realismo config.basemetals.warning.content_mode.title=¿Cambiar el modo de contenido de Base Metals? config.basemetals.warning.content_mode.message=¿Cambiar de %s a %s? Las recetas, los intercambios, el botín y las integraciones cambiarán después de reiniciar. -config.basemetals.warning.content_mode.realism=¿Cambiar de %s a %s? Los perfiles de mundo existentes de OreSpawn se conservarán; desactiva manualmente las reglas de adamantina, glacierro y estrellacero cuando sea necesario. config.basemetals.warning.confirm=Guardar y reiniciar más tarde config.basemetals.warning.disable_ores.title=Se requiere una acción en las reglas de OreSpawn config.basemetals.warning.disable_ores.message=Antes de reiniciar, desactiva estas reglas en OreSpawn o la falta de sus bloques de salida invalidará el proveedor: %s @@ -594,4 +596,3 @@ config.basemetals.material.prismarine=Prismarina config.basemetals.material.redstone=Redstone config.basemetals.content_mode.high_fantasy.description=Todo el contenido histórico y las vías de obtención de Base Metals siguen disponibles. config.basemetals.content_mode.low_fantasy.description=Los materiales fantásticos permanecen, pero se ocultan las recetas de equipo y construcción poco plausibles. -config.basemetals.content_mode.realism.description=Se aplican las restricciones de Baja fantasía y se desactiva la obtención normal de materiales míticos. diff --git a/src/main/resources/assets/basemetals/lang/fr_ca.lang b/src/main/resources/assets/basemetals/lang/fr_ca.lang index 3260fcbd..ea82991e 100644 --- a/src/main/resources/assets/basemetals/lang/fr_ca.lang +++ b/src/main/resources/assets/basemetals/lang/fr_ca.lang @@ -1,3 +1,7 @@ +achievement.cupronickel_maker=Cuivre-nickel +achievement.pewter_maker=Étain +achievement.pewter_maker.desc=Combinez des poudres d'étain, de cuivre et de plomb pour fabriquer de l'étain allié. + nei.basemetals.recipehandler.crusher.name=Blocs/éléments broyés itemGroup.basemetals.blocks=Base Metals Blocks @@ -547,13 +551,11 @@ config.basemetals.category.forced_traits=Traits forcés config.basemetals.category.forced_traits.tooltip=Force l’enregistrement des traits MMDLib pour les matériaux de Base Metals. config.basemetals.option.achievements=Succès config.basemetals.option.content_mode=Mode de contenu -config.basemetals.option.content_mode.tooltip=Choisissez Fantaisie élevée, Fantaisie modérée ou Réalisme. La politique choisie prend effet après le redémarrage de Minecraft. +config.basemetals.option.content_mode.tooltip=Choisissez Fantaisie élevée ou Fantaisie modérée. La politique choisie prend effet après le redémarrage de Minecraft. config.basemetals.content_mode.high_fantasy=Fantaisie élevée config.basemetals.content_mode.low_fantasy=Fantaisie modérée -config.basemetals.content_mode.realism=Réalisme config.basemetals.warning.content_mode.title=Modifier le mode de contenu de Base Metals ? config.basemetals.warning.content_mode.message=Passer de %s à %s ? Les recettes, échanges, butins et intégrations changeront après le redémarrage. -config.basemetals.warning.content_mode.realism=Passer de %s à %s ? Les profils de monde OreSpawn existants sont conservés ; désactivez manuellement les règles de l’adamantin, du fer-froid et de l’acier stellaire si nécessaire. config.basemetals.warning.confirm=Enregistrer et redémarrer plus tard config.basemetals.warning.disable_ores.title=Action requise pour les règles OreSpawn config.basemetals.warning.disable_ores.message=Avant de redémarrer, désactivez ces règles dans OreSpawn, sinon l’absence de leurs blocs de sortie invalidera le fournisseur : %s @@ -596,4 +598,3 @@ config.basemetals.material.prismarine=Prismarine config.basemetals.material.redstone=Redstone config.basemetals.content_mode.high_fantasy.description=Tout le contenu historique et tous les moyens d’obtention de Base Metals restent disponibles. config.basemetals.content_mode.low_fantasy.description=Les matériaux fantastiques restent présents, mais les recettes d’équipement et de construction peu plausibles sont masquées. -config.basemetals.content_mode.realism.description=Les restrictions de Fantaisie modérée s’appliquent et l’obtention normale des matériaux mythiques est désactivée. diff --git a/src/main/resources/assets/basemetals/lang/fr_fr.lang b/src/main/resources/assets/basemetals/lang/fr_fr.lang index efbce775..cbd767f6 100644 --- a/src/main/resources/assets/basemetals/lang/fr_fr.lang +++ b/src/main/resources/assets/basemetals/lang/fr_fr.lang @@ -1,3 +1,7 @@ +achievement.cupronickel_maker=Cuivre-nickel +achievement.pewter_maker=Étain +achievement.pewter_maker.desc=Combinez des poudres d'étain, de cuivre et de plomb pour fabriquer de l'étain allié. + nei.basemetals.recipehandler.crusher.name=Blocs/éléments broyés itemGroup.basemetals.blocks=Base Metals Blocks @@ -547,13 +551,11 @@ config.basemetals.category.forced_traits=Traits forcés config.basemetals.category.forced_traits.tooltip=Force l’enregistrement des traits MMDLib pour les matériaux de Base Metals. config.basemetals.option.achievements=Succès config.basemetals.option.content_mode=Mode de contenu -config.basemetals.option.content_mode.tooltip=Choisissez Fantaisie élevée, Fantaisie modérée ou Réalisme. La politique choisie prend effet après le redémarrage de Minecraft. +config.basemetals.option.content_mode.tooltip=Choisissez Fantaisie élevée ou Fantaisie modérée. La politique choisie prend effet après le redémarrage de Minecraft. config.basemetals.content_mode.high_fantasy=Fantaisie élevée config.basemetals.content_mode.low_fantasy=Fantaisie modérée -config.basemetals.content_mode.realism=Réalisme config.basemetals.warning.content_mode.title=Modifier le mode de contenu de Base Metals ? config.basemetals.warning.content_mode.message=Passer de %s à %s ? Les recettes, échanges, butins et intégrations changeront après le redémarrage. -config.basemetals.warning.content_mode.realism=Passer de %s à %s ? Les profils de monde OreSpawn existants sont conservés ; désactivez manuellement les règles de l’adamantin, du fer-froid et de l’acier stellaire si nécessaire. config.basemetals.warning.confirm=Enregistrer et redémarrer plus tard config.basemetals.warning.disable_ores.title=Action requise pour les règles OreSpawn config.basemetals.warning.disable_ores.message=Avant de redémarrer, désactivez ces règles dans OreSpawn, sinon l’absence de leurs blocs de sortie invalidera le fournisseur : %s @@ -596,4 +598,3 @@ config.basemetals.material.prismarine=Prismarine config.basemetals.material.redstone=Redstone config.basemetals.content_mode.high_fantasy.description=Tout le contenu historique et tous les moyens d’obtention de Base Metals restent disponibles. config.basemetals.content_mode.low_fantasy.description=Les matériaux fantastiques restent présents, mais les recettes d’équipement et de construction peu plausibles sont masquées. -config.basemetals.content_mode.realism.description=Les restrictions de Fantaisie modérée s’appliquent et l’obtention normale des matériaux mythiques est désactivée. diff --git a/src/main/resources/assets/basemetals/lang/it_it.lang b/src/main/resources/assets/basemetals/lang/it_it.lang index b8091dd2..3edd0b35 100644 --- a/src/main/resources/assets/basemetals/lang/it_it.lang +++ b/src/main/resources/assets/basemetals/lang/it_it.lang @@ -1,3 +1,7 @@ +achievement.cupronickel_maker=Cupronichel +achievement.pewter_maker=Peltro +achievement.pewter_maker.desc=Combina polvere di stagno, rame e piombo per ottenere peltro. + language_support_goals=english (en_US,en_EN,en_CA,en_GB, en_AU, en_PT), italian(IT_it), spanish (es_MX,es_ES), simplified chinese (zh_CN), japanese (ja_JA), portugese (pt_BR), german (de_DE) itemGroup.basemetals.blocks=Base Metals Blocks @@ -542,13 +546,11 @@ config.basemetals.category.forced_traits=Tratti forzati config.basemetals.category.forced_traits.tooltip=Forza la registrazione dei tratti MMDLib per i materiali di Base Metals. config.basemetals.option.achievements=Obiettivi config.basemetals.option.content_mode=Modalità contenuti -config.basemetals.option.content_mode.tooltip=Scegli Alta fantasia, Bassa fantasia o Realismo. La politica selezionata ha effetto dopo il riavvio di Minecraft. +config.basemetals.option.content_mode.tooltip=Scegli Alta fantasia o Bassa fantasia. La politica selezionata ha effetto dopo il riavvio di Minecraft. config.basemetals.content_mode.high_fantasy=Alta fantasia config.basemetals.content_mode.low_fantasy=Bassa fantasia -config.basemetals.content_mode.realism=Realismo config.basemetals.warning.content_mode.title=Cambiare la modalità contenuti di Base Metals? config.basemetals.warning.content_mode.message=Passare da %s a %s? Ricette, scambi, bottini e integrazioni cambieranno dopo il riavvio. -config.basemetals.warning.content_mode.realism=Passare da %s a %s? I profili mondo OreSpawn esistenti vengono conservati; disattiva manualmente le regole di adamantio, ferro freddo e acciaio stellare quando necessario. config.basemetals.warning.confirm=Salva e riavvia più tardi config.basemetals.warning.disable_ores.title=Azione richiesta per le regole OreSpawn config.basemetals.warning.disable_ores.message=Prima di riavviare, disattiva queste regole in OreSpawn, altrimenti i blocchi di uscita mancanti invalideranno il fornitore: %s @@ -591,4 +593,3 @@ config.basemetals.material.prismarine=Prismarino config.basemetals.material.redstone=Redstone config.basemetals.content_mode.high_fantasy.description=Tutti i contenuti storici e i metodi di ottenimento di Base Metals restano disponibili. config.basemetals.content_mode.low_fantasy.description=I materiali fantastici restano disponibili, ma le ricette poco plausibili per equipaggiamento e costruzioni vengono nascoste. -config.basemetals.content_mode.realism.description=Si applicano le restrizioni di Bassa fantasia e viene disattivato il normale ottenimento dei materiali mitici. diff --git a/src/main/resources/assets/basemetals/lang/ja_jp.lang b/src/main/resources/assets/basemetals/lang/ja_jp.lang index 2082e999..fa6bef28 100644 --- a/src/main/resources/assets/basemetals/lang/ja_jp.lang +++ b/src/main/resources/assets/basemetals/lang/ja_jp.lang @@ -1,3 +1,40 @@ +achievement.this_is_new=新しい金属… +achievement.this_is_new.desc=Base Metals の金属インゴットを精錬する +achievement.blocktastic=ブロック万歳! +achievement.blocktastic.desc=鉄と金以外の Base Metals の金属ブロックを設置する +achievement.geologist=地質学者 +achievement.geologist.desc=破砕ハンマーをクラフトする +achievement.metallurgy=冶金術 +achievement.metallurgy.desc=合金の混合粉末をクラフトする +achievement.aquarium_maker=アクアリウム +achievement.aquarium_maker.desc=銅と亜鉛の粉末にプリズマリンの結晶を加えてアクアリウムを作る +achievement.brass_maker=黄銅 +achievement.brass_maker.desc=銅と亜鉛の粉末を混ぜて黄銅を作る +achievement.bronze_maker=青銅 +achievement.bronze_maker.desc=銅とスズの粉末を混ぜて青銅を作る +achievement.cupronickel_maker=白銅 +achievement.cupronickel_maker.desc=銅とニッケルの粉末を混ぜて白銅を作る +achievement.electrum_maker=エレクトラム +achievement.electrum_maker.desc=銀と金の粉末を混ぜてエレクトラムを作る +achievement.invar_maker=インバー +achievement.invar_maker.desc=鉄とニッケルの粉末を混ぜてインバーを作る +achievement.mithril_maker=ミスリル +achievement.mithril_maker.desc=銀、冷鉄、水銀の粉末を混ぜてミスリルを作る +achievement.pewter_maker=ピューター +achievement.pewter_maker.desc=スズ、銅、鉛の粉末を混ぜてピューターを作る +achievement.steel_maker=鋼 +achievement.steel_maker.desc=鉄と木炭の粉末を混ぜて鋼を作る +achievement.angel_of_death=死の天使 +achievement.angel_of_death.desc=ミスリルの防具を一式装備し、ミスリルの剣を手に持つ +achievement.scuba_diver=スキューバダイバー +achievement.scuba_diver.desc=アクアリウムの防具を一式装備して水中に潜る +achievement.demon_slayer=悪魔狩り +achievement.demon_slayer.desc=冷鉄の防具を一式装備し、冷鉄の剣を手に持つ +achievement.juggernaut=ジャガーノート +achievement.juggernaut.desc=アダマントの防具を一式装備する +achievement.moon_boots=ムーンウォーカー +achievement.moon_boots.desc=星鋼のブーツを装備する + #Created by MrTrollNugNug(Cazsius) 12/17/16 #Note: All Catagories are sorted by Relevance. All Subcatagories are sorted... #in Alphabetical Order. @@ -1882,13 +1919,11 @@ config.basemetals.category.forced_traits=強制特性 config.basemetals.category.forced_traits.tooltip=Base Metals 素材の MMDLib 特性登録を強制します。 config.basemetals.option.achievements=実績 config.basemetals.option.content_mode=コンテンツモード -config.basemetals.option.content_mode.tooltip=ハイファンタジー、ローファンタジー、リアリズムから選択します。選択した方針は Minecraft の再起動後に有効になります。 +config.basemetals.option.content_mode.tooltip=ハイファンタジーまたはローファンタジーから選択します。選択した方針は Minecraft の再起動後に有効になります。 config.basemetals.content_mode.high_fantasy=ハイファンタジー config.basemetals.content_mode.low_fantasy=ローファンタジー -config.basemetals.content_mode.realism=リアリズム config.basemetals.warning.content_mode.title=Base Metals のコンテンツモードを変更しますか? config.basemetals.warning.content_mode.message=%s から %s に変更しますか?再起動後にレシピ、取引、戦利品、連携内容が変更されます。 -config.basemetals.warning.content_mode.realism=%s から %s に変更しますか?既存の OreSpawn ワールドプロファイルは保持されます。必要に応じてアダマント、コールドアイアン、スタースチールのルールを手動で無効にしてください。 config.basemetals.warning.confirm=保存して後で再起動 config.basemetals.warning.disable_ores.title=OreSpawn ルールの操作が必要です config.basemetals.warning.disable_ores.message=再起動前に OreSpawn で次のルールを無効にしてください。出力ブロックが存在しないとプロバイダーが無効になります: %s @@ -1931,4 +1966,3 @@ config.basemetals.material.prismarine=プリズマリン config.basemetals.material.redstone=レッドストーン config.basemetals.content_mode.high_fantasy.description=従来の Base Metals コンテンツと入手経路をすべて利用できます。 config.basemetals.content_mode.low_fantasy.description=ファンタジー素材は残りますが、不自然な装備や建築レシピは非表示になります。 -config.basemetals.content_mode.realism.description=ローファンタジーの制限に加え、神話素材の通常の入手が無効になります。 diff --git a/src/main/resources/assets/basemetals/lang/nl_nl.lang b/src/main/resources/assets/basemetals/lang/nl_nl.lang index 6891ace5..ffeefe01 100644 --- a/src/main/resources/assets/basemetals/lang/nl_nl.lang +++ b/src/main/resources/assets/basemetals/lang/nl_nl.lang @@ -1,3 +1,7 @@ +achievement.cupronickel_maker=Kopernikkel +achievement.pewter_maker=Tinlegering +achievement.pewter_maker.desc=Meng tin-, koper- en loodpoeder om een tinlegering te maken. + itemGroup.basemetals.blocks=Base Metals Blocks itemGroup.basemetals.combat=Base Metals Combat itemGroup.basemetals.items=Base Metals Items @@ -545,13 +549,11 @@ config.basemetals.category.forced_traits=Geforceerde eigenschappen config.basemetals.category.forced_traits.tooltip=Forceer registratie van MMDLib-eigenschappen voor Base Metals-materialen. config.basemetals.option.achievements=Prestaties config.basemetals.option.content_mode=Inhoudsmodus -config.basemetals.option.content_mode.tooltip=Kies Hoge fantasie, Lage fantasie of Realisme. Het gekozen beleid wordt actief nadat Minecraft opnieuw is gestart. +config.basemetals.option.content_mode.tooltip=Kies Hoge fantasie of Lage fantasie. Het gekozen beleid wordt actief nadat Minecraft opnieuw is gestart. config.basemetals.content_mode.high_fantasy=Hoge fantasie config.basemetals.content_mode.low_fantasy=Lage fantasie -config.basemetals.content_mode.realism=Realisme config.basemetals.warning.content_mode.title=De inhoudsmodus van Base Metals wijzigen? config.basemetals.warning.content_mode.message=Wijzigen van %s naar %s? Recepten, handel, buit en integraties veranderen na het opnieuw opstarten. -config.basemetals.warning.content_mode.realism=Wijzigen van %s naar %s? Bestaande OreSpawn-wereldprofielen blijven behouden; schakel waar nodig de regels voor adamant, koudijzer en sterrenstaal handmatig uit. config.basemetals.warning.confirm=Opslaan en later opnieuw opstarten config.basemetals.warning.disable_ores.title=Actie voor OreSpawn-regels vereist config.basemetals.warning.disable_ores.message=Schakel vóór het opnieuw opstarten deze regels in OreSpawn uit, anders maken ontbrekende uitvoerblokken de provider ongeldig: %s @@ -594,4 +596,3 @@ config.basemetals.material.prismarine=Prismarien config.basemetals.material.redstone=Redstone config.basemetals.content_mode.high_fantasy.description=Alle historische Base Metals-inhoud en verkrijgingsroutes blijven beschikbaar. config.basemetals.content_mode.low_fantasy.description=Fantasiematerialen blijven bestaan, maar onwaarschijnlijke uitrustings- en bouwrecepten worden verborgen. -config.basemetals.content_mode.realism.description=De beperkingen van Lage fantasie gelden en normale verkrijging van mythische materialen is uitgeschakeld. diff --git a/src/main/resources/assets/basemetals/lang/pt_br.lang b/src/main/resources/assets/basemetals/lang/pt_br.lang index e296e15e..998f7119 100644 --- a/src/main/resources/assets/basemetals/lang/pt_br.lang +++ b/src/main/resources/assets/basemetals/lang/pt_br.lang @@ -1,3 +1,7 @@ +achievement.cupronickel_maker=Cuproníquel +achievement.pewter_maker=Peltre +achievement.pewter_maker.desc=Combine pó de estanho, cobre e chumbo para produzir peltre. + language_support_goals=english (en_US,en_EN,en_CA,en_GB, en_AU, en_PT), spanish (es_MX,es_ES), simplified chinese (zh_CN), portugese(pt_BR), italian(IT_it), japanese (ja_JA), portugese (pt_BR), german (de_DE) itemGroup.basemetals.blocks=Base Metals Blocks @@ -545,13 +549,11 @@ config.basemetals.category.forced_traits=Características forçadas config.basemetals.category.forced_traits.tooltip=Force o registro de características do MMDLib para materiais do Base Metals. config.basemetals.option.achievements=Conquistas config.basemetals.option.content_mode=Modo de conteúdo -config.basemetals.option.content_mode.tooltip=Escolha Alta fantasia, Baixa fantasia ou Realismo. A política selecionada entra em vigor após reiniciar o Minecraft. +config.basemetals.option.content_mode.tooltip=Escolha Alta fantasia ou Baixa fantasia. A política selecionada entra em vigor após reiniciar o Minecraft. config.basemetals.content_mode.high_fantasy=Alta fantasia config.basemetals.content_mode.low_fantasy=Baixa fantasia -config.basemetals.content_mode.realism=Realismo config.basemetals.warning.content_mode.title=Alterar o modo de conteúdo do Base Metals? config.basemetals.warning.content_mode.message=Alterar de %s para %s? Receitas, trocas, saques e integrações mudarão após reiniciar. -config.basemetals.warning.content_mode.realism=Alterar de %s para %s? Os perfis de mundo existentes do OreSpawn serão preservados; desative manualmente as regras de magnetita, ferro-frio e ferro-estrela quando necessário. config.basemetals.warning.confirm=Salvar e reiniciar mais tarde config.basemetals.warning.disable_ores.title=É necessária uma ação nas regras do OreSpawn config.basemetals.warning.disable_ores.message=Antes de reiniciar, desative estas regras no OreSpawn; caso contrário, a ausência dos blocos de saída invalidará o provedor: %s @@ -594,4 +596,3 @@ config.basemetals.material.prismarine=Prismarinho config.basemetals.material.redstone=Redstone config.basemetals.content_mode.high_fantasy.description=Todo o conteúdo histórico e as formas de obtenção do Base Metals permanecem disponíveis. config.basemetals.content_mode.low_fantasy.description=Os materiais fantásticos permanecem, mas receitas pouco plausíveis de equipamentos e construções ficam ocultas. -config.basemetals.content_mode.realism.description=As restrições de Baixa fantasia são aplicadas e a obtenção normal de materiais míticos é desativada. diff --git a/src/main/resources/assets/basemetals/lang/ru_ru.lang b/src/main/resources/assets/basemetals/lang/ru_ru.lang index ca741b9c..5776a9ba 100644 --- a/src/main/resources/assets/basemetals/lang/ru_ru.lang +++ b/src/main/resources/assets/basemetals/lang/ru_ru.lang @@ -1,3 +1,6 @@ +achievement.pewter_maker=Пьютер +achievement.pewter_maker.desc=Смешайте порошки олова, меди и свинца, чтобы получить пьютер. + # Base Metals 1.12-2.5.0-beta3.51 # Translated by Grey Mamon (grey.mamon@gmail.com) 11.28.2017 # Примечание: все категории сортируются по релевантности. @@ -1859,13 +1862,11 @@ config.basemetals.category.forced_traits=Принудительные свойс config.basemetals.category.forced_traits.tooltip=Принудительно регистрировать свойства MMDLib для материалов Base Metals. config.basemetals.option.achievements=Достижения config.basemetals.option.content_mode=Режим содержимого -config.basemetals.option.content_mode.tooltip=Выберите «Высокое фэнтези», «Низкое фэнтези» или «Реализм». Выбранная политика вступит в силу после перезапуска Minecraft. +config.basemetals.option.content_mode.tooltip=Выберите «Высокое фэнтези» или «Низкое фэнтези». Выбранная политика вступит в силу после перезапуска Minecraft. config.basemetals.content_mode.high_fantasy=Высокое фэнтези config.basemetals.content_mode.low_fantasy=Низкое фэнтези -config.basemetals.content_mode.realism=Реализм config.basemetals.warning.content_mode.title=Изменить режим содержимого Base Metals? config.basemetals.warning.content_mode.message=Переключиться с %s на %s? Рецепты, торговля, добыча и интеграции изменятся после перезапуска. -config.basemetals.warning.content_mode.realism=Переключиться с %s на %s? Существующие профили миров OreSpawn сохранятся; при необходимости вручную отключите правила адамантина, хладожелеза и звёздной стали. config.basemetals.warning.confirm=Сохранить и перезапустить позже config.basemetals.warning.disable_ores.title=Требуется действие с правилами OreSpawn config.basemetals.warning.disable_ores.message=Перед перезапуском отключите эти правила в OreSpawn, иначе отсутствие выходных блоков сделает поставщика недействительным: %s @@ -1908,4 +1909,3 @@ config.basemetals.material.prismarine=Призмарин config.basemetals.material.redstone=Редстоун config.basemetals.content_mode.high_fantasy.description=Всё историческое содержимое Base Metals и способы его получения остаются доступными. config.basemetals.content_mode.low_fantasy.description=Фэнтезийные материалы остаются, но неправдоподобные рецепты снаряжения и строительства скрываются. -config.basemetals.content_mode.realism.description=Применяются ограничения Низкого фэнтези, а обычное получение мифических материалов отключается. diff --git a/src/main/resources/assets/basemetals/lang/zh_cn.lang b/src/main/resources/assets/basemetals/lang/zh_cn.lang index 7c07e362..3fe24db1 100644 --- a/src/main/resources/assets/basemetals/lang/zh_cn.lang +++ b/src/main/resources/assets/basemetals/lang/zh_cn.lang @@ -61,7 +61,7 @@ achievement.invar_maker.desc=混合铁粉和镍粉,并烧制因瓦合金 achievement.juggernaut.desc=穿上全套艾德曼金属装备 achievement.metallurgy.desc=合成任何一种合金粉末 achievement.mithril_maker.desc=混合银粉、寒铁粉和液态汞,并烧制秘银 -achievement.pewter_maker.desc=混合???和???并烧制白镴 +achievement.pewter_maker.desc=混合锡粉、铜粉和铅粉并烧制白镴 achievement.moon_boots.desc=穿上星钢靴子 achievement.scuba_diver.desc=穿上全套海洋合金装备,并在水下游泳 achievement.steel_maker.desc=混合铁粉和炭粉,并烧制钢 @@ -1825,13 +1825,11 @@ config.basemetals.category.forced_traits=强制特性 config.basemetals.category.forced_traits.tooltip=强制为 Base Metals 材料注册 MMDLib 特性。 config.basemetals.option.achievements=成就 config.basemetals.option.content_mode=内容模式 -config.basemetals.option.content_mode.tooltip=选择高幻想、低幻想或写实模式。所选规则将在重启 Minecraft 后生效。 +config.basemetals.option.content_mode.tooltip=选择高幻想或低幻想模式。所选规则将在重启 Minecraft 后生效。 config.basemetals.content_mode.high_fantasy=高幻想 config.basemetals.content_mode.low_fantasy=低幻想 -config.basemetals.content_mode.realism=写实 config.basemetals.warning.content_mode.title=更改 Base Metals 内容模式? config.basemetals.warning.content_mode.message=从 %s 更改为 %s?重启后,配方、交易、战利品和模组联动将发生变化。 -config.basemetals.warning.content_mode.realism=从 %s 更改为 %s?现有 OreSpawn 世界配置将保留;必要时请手动禁用艾德曼金属、寒铁和星钢规则。 config.basemetals.warning.confirm=保存并稍后重启 config.basemetals.warning.disable_ores.title=需要处理 OreSpawn 规则 config.basemetals.warning.disable_ores.message=重启前请在 OreSpawn 中禁用以下规则,否则缺失输出方块会使提供程序无效:%s @@ -1874,4 +1872,3 @@ config.basemetals.material.prismarine=海晶石 config.basemetals.material.redstone=红石 config.basemetals.content_mode.high_fantasy.description=保留所有历史 Base Metals 内容和获取途径。 config.basemetals.content_mode.low_fantasy.description=保留幻想材料,但隐藏不合理的装备和建筑配方。 -config.basemetals.content_mode.realism.description=应用低幻想限制,并禁用神话材料的常规获取途径。 diff --git a/src/main/resources/assets/basemetals/lang/zh_tw.lang b/src/main/resources/assets/basemetals/lang/zh_tw.lang index 1d3bb910..268cb624 100644 --- a/src/main/resources/assets/basemetals/lang/zh_tw.lang +++ b/src/main/resources/assets/basemetals/lang/zh_tw.lang @@ -61,7 +61,7 @@ achievement.invar_maker.desc=混合鐵粉與鎳粉,燒製成殷鋼 achievement.juggernaut.desc=穿上整套精金裝甲 achievement.metallurgy.desc=混合任一種合金粉末 achievement.mithril_maker.desc=混合銀、寒鐵粉末和水銀,並燒製秘銀 -achievement.pewter_maker.desc=混合 ??? 和 ??? 粉末來製造白鑞 +achievement.pewter_maker.desc=混合錫粉、銅粉與鉛粉來製造白鑞 achievement.moon_boots.desc=穿上一雙星鋼靴 achievement.scuba_diver.desc=穿上海洋合金套裝並潛入水中 achievement.steel_maker.desc=混合鐵粉和碳粉,並燒製成鋼 @@ -1899,13 +1899,11 @@ config.basemetals.category.forced_traits=強制特性 config.basemetals.category.forced_traits.tooltip=強制為 Base Metals 材料註冊 MMDLib 特性。 config.basemetals.option.achievements=成就 config.basemetals.option.content_mode=內容模式 -config.basemetals.option.content_mode.tooltip=選擇高幻想、低幻想或寫實模式。所選規則會在重新啟動 Minecraft 後生效。 +config.basemetals.option.content_mode.tooltip=選擇高幻想或低幻想模式。所選規則會在重新啟動 Minecraft 後生效。 config.basemetals.content_mode.high_fantasy=高幻想 config.basemetals.content_mode.low_fantasy=低幻想 -config.basemetals.content_mode.realism=寫實 config.basemetals.warning.content_mode.title=變更 Base Metals 內容模式? config.basemetals.warning.content_mode.message=從 %s 變更為 %s?重新啟動後,配方、交易、戰利品與模組整合會隨之變更。 -config.basemetals.warning.content_mode.realism=從 %s 變更為 %s?現有 OreSpawn 世界設定檔會保留;必要時請手動停用精金、寒鐵與星鋼規則。 config.basemetals.warning.confirm=儲存並稍後重新啟動 config.basemetals.warning.disable_ores.title=需要處理 OreSpawn 規則 config.basemetals.warning.disable_ores.message=重新啟動前請在 OreSpawn 中停用以下規則,否則缺少輸出方塊會使提供者失效:%s @@ -1948,4 +1946,3 @@ config.basemetals.material.prismarine=海磷石 config.basemetals.material.redstone=紅石 config.basemetals.content_mode.high_fantasy.description=保留所有歷史 Base Metals 內容與取得途徑。 config.basemetals.content_mode.low_fantasy.description=保留幻想材料,但隱藏不合理的裝備與建築配方。 -config.basemetals.content_mode.realism.description=套用低幻想限制,並停用神話材料的一般取得途徑。 diff --git a/src/main/resources/assets/basemetals/recipes/_factories.json b/src/main/resources/assets/basemetals/recipes/_factories.json index f55fe129..a93bcb26 100644 --- a/src/main/resources/assets/basemetals/recipes/_factories.json +++ b/src/main/resources/assets/basemetals/recipes/_factories.json @@ -6,6 +6,6 @@ }, "recipes": { "variableOutputOre": "com.mcmoddev.lib.recipe.factories.ConfigVariedOutput", - "armor_repair": "com.mcmoddev.lib.recipe.factories.ArmorRepair" + "armor_repair": "com.mcmoddev.basemetals.recipe.PlateRepairFactory" } } diff --git a/src/main/resources/assets/basemetals/recipes/activator_rail.json b/src/main/resources/assets/basemetals/recipes/activator_rail.json index b210a85a..544cc517 100644 --- a/src/main/resources/assets/basemetals/recipes/activator_rail.json +++ b/src/main/resources/assets/basemetals/recipes/activator_rail.json @@ -25,5 +25,5 @@ "item": "minecraft:activator_rail", "count": 6 }, - "group": "vanilla" + "group": "minecraft:activator_rail" } diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_anvil.json b/src/main/resources/assets/basemetals/recipes/adamantine_anvil.json index b238919f..27182026 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_anvil.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_anvil.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" + "group": "basemetals:adamantine_anvil" } diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_arrow.json b/src/main/resources/assets/basemetals/recipes/adamantine_arrow.json index f28d8cda..4c44e24f 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:adamantine_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_axe.json b/src/main/resources/assets/basemetals/recipes/adamantine_axe.json index c69ff654..3050f0fa 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_axe.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:adamantine_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_bars_1.json b/src/main/resources/assets/basemetals/recipes/adamantine_bars_1.json index 337b7f7e..98f91ff9 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:adamantine_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_bars_2.json b/src/main/resources/assets/basemetals/recipes/adamantine_bars_2.json index 994bdb19..2bbe3108 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:adamantine_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_block.json b/src/main/resources/assets/basemetals/recipes/adamantine_block.json index 94e0d0fc..a538d5fd 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_block.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:adamantine_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_block_ingot.json b/src/main/resources/assets/basemetals/recipes/adamantine_block_ingot.json index 3ef809db..998d9135 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:adamantine_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:adamantine_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_bolt.json b/src/main/resources/assets/basemetals/recipes/adamantine_bolt.json index 8b985eb4..bb25b8aa 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:adamantine_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_boots.json b/src/main/resources/assets/basemetals/recipes/adamantine_boots.json index ec27e420..44c2c474 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_boots.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:adamantine_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/adamantine_boots_plate_repair.json index 0f9e8944..1d4af550 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Adamantine", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_bow.json b/src/main/resources/assets/basemetals/recipes/adamantine_bow.json index 42de84ac..bb681fa2 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_bow.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:adamantine_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_button.json b/src/main/resources/assets/basemetals/recipes/adamantine_button.json index 6762a464..accbe1d0 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_button.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:adamantine_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_chestplate.json b/src/main/resources/assets/basemetals/recipes/adamantine_chestplate.json index 0b8c0602..70fd051c 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:adamantine_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/adamantine_chestplate_plate_repair.json index ec6e7d3d..af92d841 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Adamantine", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_crackhammer.json b/src/main/resources/assets/basemetals/recipes/adamantine_crackhammer.json index 6854f0d5..0d4718c8 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:adamantine_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_crossbow.json b/src/main/resources/assets/basemetals/recipes/adamantine_crossbow.json index bac01ebd..ef738778 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:adamantine_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_door.json b/src/main/resources/assets/basemetals/recipes/adamantine_door.json index 785ca9f8..a423782b 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_door.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:adamantine_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_fishingrod.json b/src/main/resources/assets/basemetals/recipes/adamantine_fishingrod.json index fe17232b..4181d1ef 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:adamantine_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_gear.json b/src/main/resources/assets/basemetals/recipes/adamantine_gear.json index 2c05ba12..db6f40ee 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_gear.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:adamantine_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_helmet.json b/src/main/resources/assets/basemetals/recipes/adamantine_helmet.json index 99b0c079..bedf6a0f 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:adamantine_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/adamantine_helmet_plate_repair.json index c2986843..113257a8 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Adamantine", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_hoe.json b/src/main/resources/assets/basemetals/recipes/adamantine_hoe.json index 24fba249..853e855b 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:adamantine_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_horsearmor.json b/src/main/resources/assets/basemetals/recipes/adamantine_horsearmor.json index d1fecfe9..1e1ca5e4 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:adamantine_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_ingot.json b/src/main/resources/assets/basemetals/recipes/adamantine_ingot.json index 2b828d3c..d7921c7f 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:adamantine_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_leggings.json b/src/main/resources/assets/basemetals/recipes/adamantine_leggings.json index 313cdc98..2279c849 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:adamantine_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/adamantine_leggings_plate_repair.json index 35cff2ec..b17c7048 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Adamantine", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_lever.json b/src/main/resources/assets/basemetals/recipes/adamantine_lever.json index 352d5233..24de1343 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_lever.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:adamantine_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_nugget.json b/src/main/resources/assets/basemetals/recipes/adamantine_nugget.json index 47caba58..66ad5c5c 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:adamantine_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_pickaxe.json b/src/main/resources/assets/basemetals/recipes/adamantine_pickaxe.json index a964707f..b244c212 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:adamantine_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_plate.json b/src/main/resources/assets/basemetals/recipes/adamantine_plate.json index 0c4c0433..0e2ca640 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_plate.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:adamantine_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_powder.json b/src/main/resources/assets/basemetals/recipes/adamantine_powder.json index ea7f5578..0befd883 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_powder.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:adamantine_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_pressureplate.json b/src/main/resources/assets/basemetals/recipes/adamantine_pressureplate.json index 0a0ba870..e5b4e9a8 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:adamantine_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_rod.json b/src/main/resources/assets/basemetals/recipes/adamantine_rod.json index f5e1edf2..b834ed32 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_rod.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:adamantine_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_scythe.json b/src/main/resources/assets/basemetals/recipes/adamantine_scythe.json index 68e93ab2..1b564431 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:adamantine_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_shears.json b/src/main/resources/assets/basemetals/recipes/adamantine_shears.json index faaa0ce9..a23668d5 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_shears.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:adamantine_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_shield.json b/src/main/resources/assets/basemetals/recipes/adamantine_shield.json index bffecc60..8562770b 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_shield.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:adamantine_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/adamantine_shield_plate_repair.json index 82dc6575..d4a0d3b2 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Adamantine", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_shovel.json b/src/main/resources/assets/basemetals/recipes/adamantine_shovel.json index ab27b22e..64d2ce4a 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:adamantine_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_slab.json b/src/main/resources/assets/basemetals/recipes/adamantine_slab.json index 489709ed..c3307583 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_slab.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:adamantine_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_smallpowder.json b/src/main/resources/assets/basemetals/recipes/adamantine_smallpowder.json index 64c178bf..426ae705 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:adamantine_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_stairs.json b/src/main/resources/assets/basemetals/recipes/adamantine_stairs.json index 9c6bfbea..3ea8f13d 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:adamantine_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_sword.json b/src/main/resources/assets/basemetals/recipes/adamantine_sword.json index 6f35e55e..98de3cc4 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_sword.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:adamantine_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_trapdoor.json b/src/main/resources/assets/basemetals/recipes/adamantine_trapdoor.json index cc16025c..66fd4173 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:adamantine_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/adamantine_wall.json b/src/main/resources/assets/basemetals/recipes/adamantine_wall.json index cee2af55..2b923a92 100644 --- a/src/main/resources/assets/basemetals/recipes/adamantine_wall.json +++ b/src/main/resources/assets/basemetals/recipes/adamantine_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:adamantine_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_arrow.json b/src/main/resources/assets/basemetals/recipes/antimony_arrow.json index cd47f650..92df9f10 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:antimony_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_axe.json b/src/main/resources/assets/basemetals/recipes/antimony_axe.json index 9b221634..bcbcbdc9 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_axe.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:antimony_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_bars_1.json b/src/main/resources/assets/basemetals/recipes/antimony_bars_1.json index 3dfe636a..51a066e0 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:antimony_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_bars_2.json b/src/main/resources/assets/basemetals/recipes/antimony_bars_2.json index c19d92a4..3dc09ed7 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:antimony_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_block.json b/src/main/resources/assets/basemetals/recipes/antimony_block.json index a2381506..5ab11313 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_block.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:antimony_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_block_ingot.json b/src/main/resources/assets/basemetals/recipes/antimony_block_ingot.json index 316ec169..c9dcdd54 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:antimony_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:antimony_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_bolt.json b/src/main/resources/assets/basemetals/recipes/antimony_bolt.json index cb449d8e..0e4f4609 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:antimony_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_boots.json b/src/main/resources/assets/basemetals/recipes/antimony_boots.json index cd486528..94c7980f 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_boots.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:antimony_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/antimony_boots_plate_repair.json index 8164bc82..2f9d7918 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Antimony", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/antimony_bow.json b/src/main/resources/assets/basemetals/recipes/antimony_bow.json index 98a7db4a..891011b3 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_bow.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:antimony_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_button.json b/src/main/resources/assets/basemetals/recipes/antimony_button.json index f9142c45..37a53bc6 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_button.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:antimony_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_chestplate.json b/src/main/resources/assets/basemetals/recipes/antimony_chestplate.json index 95b0f467..7929b41a 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:antimony_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/antimony_chestplate_plate_repair.json index dc021af2..84a187e6 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Antimony", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/antimony_crackhammer.json b/src/main/resources/assets/basemetals/recipes/antimony_crackhammer.json index a2ae48fe..872f49f5 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:antimony_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_crossbow.json b/src/main/resources/assets/basemetals/recipes/antimony_crossbow.json index d93fa3cf..913549f3 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:antimony_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_door.json b/src/main/resources/assets/basemetals/recipes/antimony_door.json index f05dca0f..88188696 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_door.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:antimony_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_fishingrod.json b/src/main/resources/assets/basemetals/recipes/antimony_fishingrod.json index 84ed7254..e39dd3c3 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:antimony_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_gear.json b/src/main/resources/assets/basemetals/recipes/antimony_gear.json index a459840a..0808d35c 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_gear.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:antimony_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_helmet.json b/src/main/resources/assets/basemetals/recipes/antimony_helmet.json index 77fd3d8f..d7fceb1f 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:antimony_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/antimony_helmet_plate_repair.json index 337e0926..1b54c70f 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Antimony", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/antimony_hoe.json b/src/main/resources/assets/basemetals/recipes/antimony_hoe.json index 6904dea2..8abb2393 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:antimony_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_horsearmor.json b/src/main/resources/assets/basemetals/recipes/antimony_horsearmor.json index 98ab95a4..9f953b5e 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:antimony_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_ingot.json b/src/main/resources/assets/basemetals/recipes/antimony_ingot.json index 7ab2276a..75a30a37 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:antimony_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_leggings.json b/src/main/resources/assets/basemetals/recipes/antimony_leggings.json index 5e43daf2..90fc9a93 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:antimony_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/antimony_leggings_plate_repair.json index d33eaf08..973d82b7 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Antimony", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/antimony_lever.json b/src/main/resources/assets/basemetals/recipes/antimony_lever.json index 8bfa00c2..bbd476f4 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_lever.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:antimony_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_nugget.json b/src/main/resources/assets/basemetals/recipes/antimony_nugget.json index 84db5d3c..d26402b0 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:antimony_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_pickaxe.json b/src/main/resources/assets/basemetals/recipes/antimony_pickaxe.json index 9a55ccd2..b091ec70 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:antimony_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_plate.json b/src/main/resources/assets/basemetals/recipes/antimony_plate.json index c0a44982..2e558326 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_plate.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:antimony_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_powder.json b/src/main/resources/assets/basemetals/recipes/antimony_powder.json index f5f8709d..217b8bc0 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_powder.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:antimony_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_pressureplate.json b/src/main/resources/assets/basemetals/recipes/antimony_pressureplate.json index 052f1445..f8c22bf8 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:antimony_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_rod.json b/src/main/resources/assets/basemetals/recipes/antimony_rod.json index 1f4e7c1e..6ecc52fc 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_rod.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:antimony_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/antimony_scythe.json b/src/main/resources/assets/basemetals/recipes/antimony_scythe.json index 316e5baa..50bc95d2 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:antimony_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/antimony_shears.json b/src/main/resources/assets/basemetals/recipes/antimony_shears.json index 2c38c8b3..6dbd9f99 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_shears.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:antimony_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_shield.json b/src/main/resources/assets/basemetals/recipes/antimony_shield.json index 1d171f77..55814007 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_shield.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:antimony_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/antimony_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/antimony_shield_plate_repair.json index eb4c4d01..7d9dd26b 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Antimony", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/antimony_shovel.json b/src/main/resources/assets/basemetals/recipes/antimony_shovel.json index 96514d77..c0d27ca2 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:antimony_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_slab.json b/src/main/resources/assets/basemetals/recipes/antimony_slab.json index 5370e520..041b863e 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_slab.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:antimony_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_smallpowder.json b/src/main/resources/assets/basemetals/recipes/antimony_smallpowder.json index ba483944..d697a6bd 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:antimony_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_stairs.json b/src/main/resources/assets/basemetals/recipes/antimony_stairs.json index 913abb32..3e75efa6 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:antimony_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_sword.json b/src/main/resources/assets/basemetals/recipes/antimony_sword.json index 57d51354..068cf8b5 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_sword.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:antimony_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_trapdoor.json b/src/main/resources/assets/basemetals/recipes/antimony_trapdoor.json index e1e9ae43..ac2023d2 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:antimony_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/antimony_wall.json b/src/main/resources/assets/basemetals/recipes/antimony_wall.json index dcc8fc8c..de47a3cd 100644 --- a/src/main/resources/assets/basemetals/recipes/antimony_wall.json +++ b/src/main/resources/assets/basemetals/recipes/antimony_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:antimony_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_arrow.json b/src/main/resources/assets/basemetals/recipes/aquarium_arrow.json index 1b5a64d4..fc474f28 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:aquarium_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_axe.json b/src/main/resources/assets/basemetals/recipes/aquarium_axe.json index 3672b695..dd6910dc 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_axe.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:aquarium_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_bars_1.json b/src/main/resources/assets/basemetals/recipes/aquarium_bars_1.json index 2c56af6f..6b142201 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:aquarium_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_bars_2.json b/src/main/resources/assets/basemetals/recipes/aquarium_bars_2.json index fd215bd7..0eccf274 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:aquarium_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_blend_base.json b/src/main/resources/assets/basemetals/recipes/aquarium_blend_base.json index 6e1a0585..b9bc598e 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_blend_base.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_blend_base.json @@ -23,7 +23,7 @@ "ore": "dustPrismarine" } ], - "group": "alloys", + "group": "basemetals:aquarium_blend", "conditions": [ { "type": "forge:and", @@ -51,4 +51,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_blend_smallblend.json b/src/main/resources/assets/basemetals/recipes/aquarium_blend_smallblend.json index 29e955fe..a0b22054 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_blend_smallblend.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_blend_smallblend.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:aquarium_blend" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_block.json b/src/main/resources/assets/basemetals/recipes/aquarium_block.json index 00ed9106..cc6c6146 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_block.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:aquarium_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_block_ingot.json b/src/main/resources/assets/basemetals/recipes/aquarium_block_ingot.json index da37a8ca..28b9c20e 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:aquarium_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:aquarium_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_bolt.json b/src/main/resources/assets/basemetals/recipes/aquarium_bolt.json index 5eba3432..3c3de5ca 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:aquarium_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_boots.json b/src/main/resources/assets/basemetals/recipes/aquarium_boots.json index 1820ed68..4dbb340b 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_boots.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:aquarium_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_bow.json b/src/main/resources/assets/basemetals/recipes/aquarium_bow.json index cc0d5d8c..81609b1d 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_bow.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:aquarium_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_button.json b/src/main/resources/assets/basemetals/recipes/aquarium_button.json index c30e549e..eaf86a2f 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_button.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:aquarium_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_chestplate.json b/src/main/resources/assets/basemetals/recipes/aquarium_chestplate.json index ce09d6c4..ba5e0042 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:aquarium_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_crackhammer.json b/src/main/resources/assets/basemetals/recipes/aquarium_crackhammer.json index bb837257..8e1b3ae6 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:aquarium_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_crossbow.json b/src/main/resources/assets/basemetals/recipes/aquarium_crossbow.json index 5409a780..22f9ddb2 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:aquarium_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_door.json b/src/main/resources/assets/basemetals/recipes/aquarium_door.json index 6a2a4bdb..81d38fb0 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_door.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:aquarium_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_fishingrod.json b/src/main/resources/assets/basemetals/recipes/aquarium_fishingrod.json index 97ee3bba..f4b015c7 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:aquarium_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_gear.json b/src/main/resources/assets/basemetals/recipes/aquarium_gear.json index b457d956..b8d15f54 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_gear.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:aquarium_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_helmet.json b/src/main/resources/assets/basemetals/recipes/aquarium_helmet.json index 1f4572e2..63f3eda2 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:aquarium_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_hoe.json b/src/main/resources/assets/basemetals/recipes/aquarium_hoe.json index ed297ba2..2a7831a9 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:aquarium_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_horsearmor.json b/src/main/resources/assets/basemetals/recipes/aquarium_horsearmor.json index 9416cca0..c13775bd 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:aquarium_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_ingot.json b/src/main/resources/assets/basemetals/recipes/aquarium_ingot.json index 1ab865c2..95b33051 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:aquarium_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_leggings.json b/src/main/resources/assets/basemetals/recipes/aquarium_leggings.json index 03732ec6..d2971214 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:aquarium_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_lever.json b/src/main/resources/assets/basemetals/recipes/aquarium_lever.json index 3537c181..e75cc522 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_lever.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:aquarium_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_nugget.json b/src/main/resources/assets/basemetals/recipes/aquarium_nugget.json index a00de2dd..8f52f3e1 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:aquarium_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_pickaxe.json b/src/main/resources/assets/basemetals/recipes/aquarium_pickaxe.json index 0b5af9b0..307d9ace 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:aquarium_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_plate.json b/src/main/resources/assets/basemetals/recipes/aquarium_plate.json index 4def5dbb..436c2e9c 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_plate.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:aquarium_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_powder.json b/src/main/resources/assets/basemetals/recipes/aquarium_powder.json index 27c9ddd5..4c378e84 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_powder.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:aquarium_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_pressureplate.json b/src/main/resources/assets/basemetals/recipes/aquarium_pressureplate.json index 00912efe..1e9a611a 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:aquarium_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_rod.json b/src/main/resources/assets/basemetals/recipes/aquarium_rod.json index 82384601..05626269 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_rod.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:aquarium_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_scythe.json b/src/main/resources/assets/basemetals/recipes/aquarium_scythe.json index 24bd9509..8bfe7ef6 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:aquarium_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_shears.json b/src/main/resources/assets/basemetals/recipes/aquarium_shears.json index 8e88000d..138fc1b2 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_shears.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:aquarium_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_shield.json b/src/main/resources/assets/basemetals/recipes/aquarium_shield.json index 48c51b07..987884c7 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_shield.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:aquarium_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_shovel.json b/src/main/resources/assets/basemetals/recipes/aquarium_shovel.json index e3718e28..4c65b739 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:aquarium_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_slab.json b/src/main/resources/assets/basemetals/recipes/aquarium_slab.json index 27135c50..0ce91862 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_slab.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:aquarium_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_smallblend_blend.json b/src/main/resources/assets/basemetals/recipes/aquarium_smallblend_blend.json index fc37351e..b1610989 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_smallblend_blend.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_smallblend_blend.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:aquarium_smallblend" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_smallpowder.json b/src/main/resources/assets/basemetals/recipes/aquarium_smallpowder.json index 9dc20bfc..db8f0bce 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:aquarium_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_stairs.json b/src/main/resources/assets/basemetals/recipes/aquarium_stairs.json index 95c4c6db..8c5514ed 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:aquarium_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_sword.json b/src/main/resources/assets/basemetals/recipes/aquarium_sword.json index 65a27f09..558b732a 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_sword.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:aquarium_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_trapdoor.json b/src/main/resources/assets/basemetals/recipes/aquarium_trapdoor.json index 4d6a00aa..9d995a29 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:aquarium_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/aquarium_wall.json b/src/main/resources/assets/basemetals/recipes/aquarium_wall.json index c215ed47..d0dfcb14 100644 --- a/src/main/resources/assets/basemetals/recipes/aquarium_wall.json +++ b/src/main/resources/assets/basemetals/recipes/aquarium_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:aquarium_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_arrow.json b/src/main/resources/assets/basemetals/recipes/bismuth_arrow.json index b04b358c..c2d6862c 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:bismuth_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_axe.json b/src/main/resources/assets/basemetals/recipes/bismuth_axe.json index 0e90321d..dc7307b5 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_axe.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:bismuth_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_bars_1.json b/src/main/resources/assets/basemetals/recipes/bismuth_bars_1.json index 9cd5ffb0..c41e8ca1 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bismuth_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_bars_2.json b/src/main/resources/assets/basemetals/recipes/bismuth_bars_2.json index 799b6cee..092badcc 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bismuth_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_block.json b/src/main/resources/assets/basemetals/recipes/bismuth_block.json index d90d1f80..2520950b 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_block.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:bismuth_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_block_ingot.json b/src/main/resources/assets/basemetals/recipes/bismuth_block_ingot.json index 343c55c5..cda39875 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:bismuth_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:bismuth_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_bolt.json b/src/main/resources/assets/basemetals/recipes/bismuth_bolt.json index d27cb203..31a305fc 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:bismuth_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_boots.json b/src/main/resources/assets/basemetals/recipes/bismuth_boots.json index 7d2c4282..f1dd421a 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_boots.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:bismuth_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/bismuth_boots_plate_repair.json index 6a7de6c5..d99bd007 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Bismuth", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_bow.json b/src/main/resources/assets/basemetals/recipes/bismuth_bow.json index 5bef3943..85ef5c12 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_bow.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:bismuth_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_button.json b/src/main/resources/assets/basemetals/recipes/bismuth_button.json index 20eb7bb6..58bc42cc 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_button.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bismuth_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_chestplate.json b/src/main/resources/assets/basemetals/recipes/bismuth_chestplate.json index aca4f0b2..0a1ab732 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:bismuth_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/bismuth_chestplate_plate_repair.json index a1219169..3e1db09a 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Bismuth", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_crackhammer.json b/src/main/resources/assets/basemetals/recipes/bismuth_crackhammer.json index aa16958f..71cdcd94 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:bismuth_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_crossbow.json b/src/main/resources/assets/basemetals/recipes/bismuth_crossbow.json index a906dc99..d711343b 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:bismuth_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_door.json b/src/main/resources/assets/basemetals/recipes/bismuth_door.json index fa10e05b..eb3319c9 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_door.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bismuth_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_fishingrod.json b/src/main/resources/assets/basemetals/recipes/bismuth_fishingrod.json index 9e7ed602..465bab8e 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bismuth_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_gear.json b/src/main/resources/assets/basemetals/recipes/bismuth_gear.json index 9d8eb6ec..77cb3f3e 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_gear.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bismuth_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_helmet.json b/src/main/resources/assets/basemetals/recipes/bismuth_helmet.json index e608bf9c..3e888dca 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:bismuth_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/bismuth_helmet_plate_repair.json index 8809434a..e3a61d26 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Bismuth", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_hoe.json b/src/main/resources/assets/basemetals/recipes/bismuth_hoe.json index 20e0c06c..96cd17e9 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:bismuth_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_horsearmor.json b/src/main/resources/assets/basemetals/recipes/bismuth_horsearmor.json index ec819f9d..6319a9d4 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:bismuth_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_ingot.json b/src/main/resources/assets/basemetals/recipes/bismuth_ingot.json index 016af44f..b1ca610b 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:bismuth_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_leggings.json b/src/main/resources/assets/basemetals/recipes/bismuth_leggings.json index 99f33000..3bf251ac 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:bismuth_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/bismuth_leggings_plate_repair.json index 5f4a1b17..cc4d61ab 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Bismuth", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_lever.json b/src/main/resources/assets/basemetals/recipes/bismuth_lever.json index 5d02ba7a..578e39ef 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_lever.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bismuth_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_nugget.json b/src/main/resources/assets/basemetals/recipes/bismuth_nugget.json index bcfb91e6..ed4c71b3 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:bismuth_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_pickaxe.json b/src/main/resources/assets/basemetals/recipes/bismuth_pickaxe.json index 467a48c5..86cc3c9f 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:bismuth_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_plate.json b/src/main/resources/assets/basemetals/recipes/bismuth_plate.json index 2230ea99..d2e76ded 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_plate.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bismuth_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_powder.json b/src/main/resources/assets/basemetals/recipes/bismuth_powder.json index 1647067f..63877160 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_powder.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:bismuth_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_pressureplate.json b/src/main/resources/assets/basemetals/recipes/bismuth_pressureplate.json index 8f5b8201..130fb2a5 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bismuth_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_rod.json b/src/main/resources/assets/basemetals/recipes/bismuth_rod.json index f5358bda..80dd994f 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_rod.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:bismuth_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_scythe.json b/src/main/resources/assets/basemetals/recipes/bismuth_scythe.json index 4b134f2a..321c3b7b 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:bismuth_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_shears.json b/src/main/resources/assets/basemetals/recipes/bismuth_shears.json index 2a86953c..bbd25f34 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_shears.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:bismuth_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_shield.json b/src/main/resources/assets/basemetals/recipes/bismuth_shield.json index ee115fe6..f4fc40a9 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_shield.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:bismuth_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/bismuth_shield_plate_repair.json index 890dffe1..5128d12e 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Bismuth", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_shovel.json b/src/main/resources/assets/basemetals/recipes/bismuth_shovel.json index df437816..6634d121 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:bismuth_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_slab.json b/src/main/resources/assets/basemetals/recipes/bismuth_slab.json index 2856e781..74cdafeb 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_slab.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bismuth_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_smallpowder.json b/src/main/resources/assets/basemetals/recipes/bismuth_smallpowder.json index ed77ed0a..9d3abd28 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:bismuth_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_stairs.json b/src/main/resources/assets/basemetals/recipes/bismuth_stairs.json index 81ba9adf..8ccd7ab8 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bismuth_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_sword.json b/src/main/resources/assets/basemetals/recipes/bismuth_sword.json index 647ada1c..2c55cee7 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_sword.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:bismuth_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_trapdoor.json b/src/main/resources/assets/basemetals/recipes/bismuth_trapdoor.json index 0f5fbe20..969a148f 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bismuth_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/bismuth_wall.json b/src/main/resources/assets/basemetals/recipes/bismuth_wall.json index 8228377f..e1122839 100644 --- a/src/main/resources/assets/basemetals/recipes/bismuth_wall.json +++ b/src/main/resources/assets/basemetals/recipes/bismuth_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bismuth_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_arrow.json b/src/main/resources/assets/basemetals/recipes/brass_arrow.json index 00750ed7..6d6a3df5 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/brass_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:brass_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_axe.json b/src/main/resources/assets/basemetals/recipes/brass_axe.json index 7be676c7..176370fd 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_axe.json +++ b/src/main/resources/assets/basemetals/recipes/brass_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:brass_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_bars_1.json b/src/main/resources/assets/basemetals/recipes/brass_bars_1.json index 7346fdc3..40332e13 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/brass_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:brass_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_bars_2.json b/src/main/resources/assets/basemetals/recipes/brass_bars_2.json index c6d43ef0..bca39d54 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/brass_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:brass_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_blend_base.json b/src/main/resources/assets/basemetals/recipes/brass_blend_base.json index 51c9a7c9..fada5e2a 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_blend_base.json +++ b/src/main/resources/assets/basemetals/recipes/brass_blend_base.json @@ -23,7 +23,7 @@ "ore": "dustZinc" } ], - "group": "alloys", + "group": "basemetals:brass_blend", "conditions": [ { "type": "forge:and", @@ -51,4 +51,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_blend_smallblend.json b/src/main/resources/assets/basemetals/recipes/brass_blend_smallblend.json index 4d3c6243..e40220a4 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_blend_smallblend.json +++ b/src/main/resources/assets/basemetals/recipes/brass_blend_smallblend.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:brass_blend" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_block.json b/src/main/resources/assets/basemetals/recipes/brass_block.json index f9548626..fe9a1aba 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_block.json +++ b/src/main/resources/assets/basemetals/recipes/brass_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:brass_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_block_ingot.json b/src/main/resources/assets/basemetals/recipes/brass_block_ingot.json index 2214878d..dc3bb7e3 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/brass_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:brass_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:brass_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_bolt.json b/src/main/resources/assets/basemetals/recipes/brass_bolt.json index 31ae8dfe..beac1be3 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/brass_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:brass_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_boots.json b/src/main/resources/assets/basemetals/recipes/brass_boots.json index 21a558a9..19b2c356 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_boots.json +++ b/src/main/resources/assets/basemetals/recipes/brass_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:brass_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/brass_boots_plate_repair.json index 4d4c2af7..7ea57766 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/brass_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Brass", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/brass_bow.json b/src/main/resources/assets/basemetals/recipes/brass_bow.json index 159c6ef5..bcf3b797 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_bow.json +++ b/src/main/resources/assets/basemetals/recipes/brass_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:brass_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_button.json b/src/main/resources/assets/basemetals/recipes/brass_button.json index a94bb6d3..d915e728 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_button.json +++ b/src/main/resources/assets/basemetals/recipes/brass_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:brass_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_chestplate.json b/src/main/resources/assets/basemetals/recipes/brass_chestplate.json index 027eaf26..914938fb 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/brass_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:brass_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/brass_chestplate_plate_repair.json index 588617a3..0e8edd0b 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/brass_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Brass", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/brass_crackhammer.json b/src/main/resources/assets/basemetals/recipes/brass_crackhammer.json index 392baddb..f5f6f7e4 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/brass_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:brass_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_crossbow.json b/src/main/resources/assets/basemetals/recipes/brass_crossbow.json index 3d0c19e6..8f783c34 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/brass_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:brass_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_door.json b/src/main/resources/assets/basemetals/recipes/brass_door.json index 1334b179..c3ca02b0 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_door.json +++ b/src/main/resources/assets/basemetals/recipes/brass_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:brass_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_fishingrod.json b/src/main/resources/assets/basemetals/recipes/brass_fishingrod.json index 48ba5b0b..a04a744f 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/brass_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:brass_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_gear.json b/src/main/resources/assets/basemetals/recipes/brass_gear.json index a3c29b9d..6148a6de 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_gear.json +++ b/src/main/resources/assets/basemetals/recipes/brass_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:brass_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_helmet.json b/src/main/resources/assets/basemetals/recipes/brass_helmet.json index 6379cc00..6764c0b8 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/brass_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:brass_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/brass_helmet_plate_repair.json index 9d23c582..84d3187b 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/brass_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Brass", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/brass_hoe.json b/src/main/resources/assets/basemetals/recipes/brass_hoe.json index 0d717782..4f2e249c 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/brass_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:brass_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_horsearmor.json b/src/main/resources/assets/basemetals/recipes/brass_horsearmor.json index 9ae9cdd0..150b5fae 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/brass_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:brass_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_ingot.json b/src/main/resources/assets/basemetals/recipes/brass_ingot.json index b458f5fa..805a8282 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/brass_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:brass_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_leggings.json b/src/main/resources/assets/basemetals/recipes/brass_leggings.json index d8a5ac8e..72ccca8e 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/brass_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:brass_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/brass_leggings_plate_repair.json index f321f697..ac9635fe 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/brass_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Brass", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/brass_lever.json b/src/main/resources/assets/basemetals/recipes/brass_lever.json index 3f5dea39..51ce513d 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_lever.json +++ b/src/main/resources/assets/basemetals/recipes/brass_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:brass_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_nugget.json b/src/main/resources/assets/basemetals/recipes/brass_nugget.json index 8b7c5bcc..600dc71e 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/brass_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:brass_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_pickaxe.json b/src/main/resources/assets/basemetals/recipes/brass_pickaxe.json index 66167ef6..4d471456 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/brass_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:brass_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_plate.json b/src/main/resources/assets/basemetals/recipes/brass_plate.json index b00d89d8..87af683c 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_plate.json +++ b/src/main/resources/assets/basemetals/recipes/brass_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:brass_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_powder.json b/src/main/resources/assets/basemetals/recipes/brass_powder.json index e4b758f8..4d9648df 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_powder.json +++ b/src/main/resources/assets/basemetals/recipes/brass_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:brass_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_pressureplate.json b/src/main/resources/assets/basemetals/recipes/brass_pressureplate.json index e8d121fa..385de212 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/brass_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:brass_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_rod.json b/src/main/resources/assets/basemetals/recipes/brass_rod.json index 8de2af10..bceef34f 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_rod.json +++ b/src/main/resources/assets/basemetals/recipes/brass_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:brass_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/brass_scythe.json b/src/main/resources/assets/basemetals/recipes/brass_scythe.json index ecc6bbda..eb09a218 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/brass_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:brass_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/brass_shears.json b/src/main/resources/assets/basemetals/recipes/brass_shears.json index 790e3dd9..c172d80c 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_shears.json +++ b/src/main/resources/assets/basemetals/recipes/brass_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:brass_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_shield.json b/src/main/resources/assets/basemetals/recipes/brass_shield.json index 030e04c5..150c510e 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_shield.json +++ b/src/main/resources/assets/basemetals/recipes/brass_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:brass_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/brass_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/brass_shield_plate_repair.json index 84a571c8..10043220 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/brass_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Brass", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/brass_shovel.json b/src/main/resources/assets/basemetals/recipes/brass_shovel.json index ccc66be6..8a0aee44 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/brass_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:brass_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_slab.json b/src/main/resources/assets/basemetals/recipes/brass_slab.json index 6f5a6ff7..82c48b51 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_slab.json +++ b/src/main/resources/assets/basemetals/recipes/brass_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:brass_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_smallblend_blend.json b/src/main/resources/assets/basemetals/recipes/brass_smallblend_blend.json index eeb36152..ecef6f04 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_smallblend_blend.json +++ b/src/main/resources/assets/basemetals/recipes/brass_smallblend_blend.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:brass_smallblend" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_smallpowder.json b/src/main/resources/assets/basemetals/recipes/brass_smallpowder.json index 39b75fb8..ef9f96c9 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/brass_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:brass_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_stairs.json b/src/main/resources/assets/basemetals/recipes/brass_stairs.json index 53cb55ad..94aa6cba 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/brass_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:brass_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_sword.json b/src/main/resources/assets/basemetals/recipes/brass_sword.json index 9fb507b0..f5cf75b2 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_sword.json +++ b/src/main/resources/assets/basemetals/recipes/brass_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:brass_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_trapdoor.json b/src/main/resources/assets/basemetals/recipes/brass_trapdoor.json index ebfc18f3..b98d3b5a 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/brass_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:brass_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/brass_wall.json b/src/main/resources/assets/basemetals/recipes/brass_wall.json index e8e79d7d..2c7a32de 100644 --- a/src/main/resources/assets/basemetals/recipes/brass_wall.json +++ b/src/main/resources/assets/basemetals/recipes/brass_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:brass_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_arrow.json b/src/main/resources/assets/basemetals/recipes/bronze_arrow.json index 7bf4c7b8..00fb954d 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:bronze_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_axe.json b/src/main/resources/assets/basemetals/recipes/bronze_axe.json index f81743bf..8bf4f795 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_axe.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:bronze_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_bars_1.json b/src/main/resources/assets/basemetals/recipes/bronze_bars_1.json index e8f87ef5..7ebec284 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bronze_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_bars_2.json b/src/main/resources/assets/basemetals/recipes/bronze_bars_2.json index 7ed43162..09ae8965 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bronze_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_blend_base.json b/src/main/resources/assets/basemetals/recipes/bronze_blend_base.json index e68dba50..a79a3ee8 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_blend_base.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_blend_base.json @@ -23,7 +23,7 @@ "ore": "dustTin" } ], - "group": "alloys", + "group": "basemetals:bronze_blend", "conditions": [ { "type": "forge:and", @@ -51,4 +51,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_blend_smallblend.json b/src/main/resources/assets/basemetals/recipes/bronze_blend_smallblend.json index dd554c93..4111bda1 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_blend_smallblend.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_blend_smallblend.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:bronze_blend" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_block.json b/src/main/resources/assets/basemetals/recipes/bronze_block.json index 819c619e..ad873d52 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_block.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:bronze_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_block_ingot.json b/src/main/resources/assets/basemetals/recipes/bronze_block_ingot.json index 656b30e3..adcba3ac 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:bronze_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:bronze_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_bolt.json b/src/main/resources/assets/basemetals/recipes/bronze_bolt.json index d1b7f550..f7057e90 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:bronze_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_boots.json b/src/main/resources/assets/basemetals/recipes/bronze_boots.json index 2b4d07e5..ef6bf372 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_boots.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:bronze_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/bronze_boots_plate_repair.json index a9d15752..60c15aaa 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Bronze", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/bronze_bow.json b/src/main/resources/assets/basemetals/recipes/bronze_bow.json index d0ca3cf3..7ff57db2 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_bow.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:bronze_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_button.json b/src/main/resources/assets/basemetals/recipes/bronze_button.json index 1aa9cc38..931e0415 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_button.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bronze_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_chestplate.json b/src/main/resources/assets/basemetals/recipes/bronze_chestplate.json index 797ef5bd..720b8162 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:bronze_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/bronze_chestplate_plate_repair.json index be1d31f7..0311fe70 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Bronze", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/bronze_crackhammer.json b/src/main/resources/assets/basemetals/recipes/bronze_crackhammer.json index ea897556..3482384e 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:bronze_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_crossbow.json b/src/main/resources/assets/basemetals/recipes/bronze_crossbow.json index 616f9d76..4891d7f9 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:bronze_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_door.json b/src/main/resources/assets/basemetals/recipes/bronze_door.json index 250aff51..934f8f15 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_door.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bronze_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_fishingrod.json b/src/main/resources/assets/basemetals/recipes/bronze_fishingrod.json index 154f7b61..105ab0f6 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bronze_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_gear.json b/src/main/resources/assets/basemetals/recipes/bronze_gear.json index 903a5a62..238a1a51 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_gear.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bronze_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_helmet.json b/src/main/resources/assets/basemetals/recipes/bronze_helmet.json index 59e96f6d..8ecf269a 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:bronze_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/bronze_helmet_plate_repair.json index 2589e927..444b5159 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Bronze", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/bronze_hoe.json b/src/main/resources/assets/basemetals/recipes/bronze_hoe.json index f40d7022..73a333c4 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:bronze_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_horsearmor.json b/src/main/resources/assets/basemetals/recipes/bronze_horsearmor.json index 64a88fba..0bbdd798 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:bronze_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_ingot.json b/src/main/resources/assets/basemetals/recipes/bronze_ingot.json index 9120e968..362213bd 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:bronze_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_leggings.json b/src/main/resources/assets/basemetals/recipes/bronze_leggings.json index d2278880..4a00f8c5 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:bronze_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/bronze_leggings_plate_repair.json index 98f334bb..113700de 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Bronze", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/bronze_lever.json b/src/main/resources/assets/basemetals/recipes/bronze_lever.json index 47491a48..2a8045fd 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_lever.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bronze_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_nugget.json b/src/main/resources/assets/basemetals/recipes/bronze_nugget.json index d91821dc..bd846b6d 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:bronze_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_pickaxe.json b/src/main/resources/assets/basemetals/recipes/bronze_pickaxe.json index 820f9e0e..2c8c8e1a 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:bronze_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_plate.json b/src/main/resources/assets/basemetals/recipes/bronze_plate.json index d368eb22..202381ef 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_plate.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bronze_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_powder.json b/src/main/resources/assets/basemetals/recipes/bronze_powder.json index 9dc83bcd..fa411ebd 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_powder.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:bronze_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_pressureplate.json b/src/main/resources/assets/basemetals/recipes/bronze_pressureplate.json index 82224772..a23e65da 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bronze_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_rod.json b/src/main/resources/assets/basemetals/recipes/bronze_rod.json index c6bae5d9..e5280735 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_rod.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:bronze_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/bronze_scythe.json b/src/main/resources/assets/basemetals/recipes/bronze_scythe.json index 1be6e0ed..21b860fb 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:bronze_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/bronze_shears.json b/src/main/resources/assets/basemetals/recipes/bronze_shears.json index d15ebcc5..d43ff471 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_shears.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:bronze_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_shield.json b/src/main/resources/assets/basemetals/recipes/bronze_shield.json index d132cf8e..319a8163 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_shield.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:bronze_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/bronze_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/bronze_shield_plate_repair.json index 1b1948cc..7a6ff7e2 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Bronze", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/bronze_shovel.json b/src/main/resources/assets/basemetals/recipes/bronze_shovel.json index d78fd19e..eb31a2e3 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:bronze_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_slab.json b/src/main/resources/assets/basemetals/recipes/bronze_slab.json index de97e71a..b0ce152c 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_slab.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bronze_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_smallblend_blend.json b/src/main/resources/assets/basemetals/recipes/bronze_smallblend_blend.json index ac4f38dd..fbee30f1 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_smallblend_blend.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_smallblend_blend.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:bronze_smallblend" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_smallpowder.json b/src/main/resources/assets/basemetals/recipes/bronze_smallpowder.json index 6e5d49b0..c0bd89ac 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:bronze_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_stairs.json b/src/main/resources/assets/basemetals/recipes/bronze_stairs.json index 498acd5b..7888bcad 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bronze_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_sword.json b/src/main/resources/assets/basemetals/recipes/bronze_sword.json index 79d3ea70..bdbde030 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_sword.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:bronze_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_trapdoor.json b/src/main/resources/assets/basemetals/recipes/bronze_trapdoor.json index 10d61d49..92f54f44 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bronze_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/bronze_wall.json b/src/main/resources/assets/basemetals/recipes/bronze_wall.json index 2e0ce1cf..59dbe608 100644 --- a/src/main/resources/assets/basemetals/recipes/bronze_wall.json +++ b/src/main/resources/assets/basemetals/recipes/bronze_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:bronze_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/charcoal_block.json b/src/main/resources/assets/basemetals/recipes/charcoal_block.json index f1022de3..e512dc4a 100644 --- a/src/main/resources/assets/basemetals/recipes/charcoal_block.json +++ b/src/main/resources/assets/basemetals/recipes/charcoal_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:charcoal_block" } diff --git a/src/main/resources/assets/basemetals/recipes/charcoal_block_dust.json b/src/main/resources/assets/basemetals/recipes/charcoal_block_dust.json index db7a42c8..9fb0791e 100644 --- a/src/main/resources/assets/basemetals/recipes/charcoal_block_dust.json +++ b/src/main/resources/assets/basemetals/recipes/charcoal_block_dust.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:charcoal_block" } diff --git a/src/main/resources/assets/basemetals/recipes/charcoal_ingot.json b/src/main/resources/assets/basemetals/recipes/charcoal_ingot.json index df6248aa..05e82066 100644 --- a/src/main/resources/assets/basemetals/recipes/charcoal_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/charcoal_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "minecraft:coal" } diff --git a/src/main/resources/assets/basemetals/recipes/charcoal_nugget.json b/src/main/resources/assets/basemetals/recipes/charcoal_nugget.json index dd381579..0f60c16d 100644 --- a/src/main/resources/assets/basemetals/recipes/charcoal_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/charcoal_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:charcoal_nugget" } diff --git a/src/main/resources/assets/basemetals/recipes/charcoal_powder.json b/src/main/resources/assets/basemetals/recipes/charcoal_powder.json index bdbb7aec..39eccf2c 100644 --- a/src/main/resources/assets/basemetals/recipes/charcoal_powder.json +++ b/src/main/resources/assets/basemetals/recipes/charcoal_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:charcoal_powder" } diff --git a/src/main/resources/assets/basemetals/recipes/charcoal_smallpowder.json b/src/main/resources/assets/basemetals/recipes/charcoal_smallpowder.json index 24d71396..bc6364cf 100644 --- a/src/main/resources/assets/basemetals/recipes/charcoal_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/charcoal_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:charcoal_smallpowder" } diff --git a/src/main/resources/assets/basemetals/recipes/coal_block_dust.json b/src/main/resources/assets/basemetals/recipes/coal_block_dust.json index 5e01f098..84a60bc4 100644 --- a/src/main/resources/assets/basemetals/recipes/coal_block_dust.json +++ b/src/main/resources/assets/basemetals/recipes/coal_block_dust.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "minecraft:coal_block" } diff --git a/src/main/resources/assets/basemetals/recipes/coal_ingot.json b/src/main/resources/assets/basemetals/recipes/coal_ingot.json index 2268dd06..7356efd9 100644 --- a/src/main/resources/assets/basemetals/recipes/coal_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/coal_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "minecraft:coal" } diff --git a/src/main/resources/assets/basemetals/recipes/coal_nugget.json b/src/main/resources/assets/basemetals/recipes/coal_nugget.json index 97cf122e..7852f80a 100644 --- a/src/main/resources/assets/basemetals/recipes/coal_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/coal_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:coal_nugget" } diff --git a/src/main/resources/assets/basemetals/recipes/coal_powder.json b/src/main/resources/assets/basemetals/recipes/coal_powder.json index 408f8607..cbed71ba 100644 --- a/src/main/resources/assets/basemetals/recipes/coal_powder.json +++ b/src/main/resources/assets/basemetals/recipes/coal_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:coal_powder" } diff --git a/src/main/resources/assets/basemetals/recipes/coal_smallpowder.json b/src/main/resources/assets/basemetals/recipes/coal_smallpowder.json index c103a3b3..016cd606 100644 --- a/src/main/resources/assets/basemetals/recipes/coal_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/coal_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:coal_smallpowder" } diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_arrow.json b/src/main/resources/assets/basemetals/recipes/coldiron_arrow.json index 1ae66597..4bddcb86 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:coldiron_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_axe.json b/src/main/resources/assets/basemetals/recipes/coldiron_axe.json index e50900b7..d2511169 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_axe.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:coldiron_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_bars_1.json b/src/main/resources/assets/basemetals/recipes/coldiron_bars_1.json index 7c91d79b..5a899b52 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:coldiron_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_bars_2.json b/src/main/resources/assets/basemetals/recipes/coldiron_bars_2.json index 00cdb2d6..a30aad03 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:coldiron_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_block.json b/src/main/resources/assets/basemetals/recipes/coldiron_block.json index 3f14b6ef..503c0d6a 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_block.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:coldiron_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_block_ingot.json b/src/main/resources/assets/basemetals/recipes/coldiron_block_ingot.json index a8b61cdb..39214def 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:coldiron_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:coldiron_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_bolt.json b/src/main/resources/assets/basemetals/recipes/coldiron_bolt.json index 47d97f71..7106b205 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:coldiron_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_boots.json b/src/main/resources/assets/basemetals/recipes/coldiron_boots.json index 4a6513b2..bb28bb34 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_boots.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:coldiron_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/coldiron_boots_plate_repair.json index 4b89873c..1e3da01b 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "ColdIron", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_bow.json b/src/main/resources/assets/basemetals/recipes/coldiron_bow.json index fa4c84f4..a1c2ed3c 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_bow.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:coldiron_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_button.json b/src/main/resources/assets/basemetals/recipes/coldiron_button.json index fb49cc93..43c63ca2 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_button.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:coldiron_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_chestplate.json b/src/main/resources/assets/basemetals/recipes/coldiron_chestplate.json index 1c7ab306..85b30b14 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:coldiron_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/coldiron_chestplate_plate_repair.json index 8b62425b..c6f1fc87 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "ColdIron", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_crackhammer.json b/src/main/resources/assets/basemetals/recipes/coldiron_crackhammer.json index c75d2b36..8535cd8e 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:coldiron_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_crossbow.json b/src/main/resources/assets/basemetals/recipes/coldiron_crossbow.json index 50e5c7b7..ffc79cbc 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:coldiron_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_door.json b/src/main/resources/assets/basemetals/recipes/coldiron_door.json index 4c1b8b9a..b0cfd0f1 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_door.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:coldiron_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_fishingrod.json b/src/main/resources/assets/basemetals/recipes/coldiron_fishingrod.json index d4f2866d..f7371941 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:coldiron_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_gear.json b/src/main/resources/assets/basemetals/recipes/coldiron_gear.json index cf855416..25ff0973 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_gear.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:coldiron_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_helmet.json b/src/main/resources/assets/basemetals/recipes/coldiron_helmet.json index f713fb91..fa0ee3f7 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:coldiron_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/coldiron_helmet_plate_repair.json index 161b01c9..bcdb24cf 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "ColdIron", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_hoe.json b/src/main/resources/assets/basemetals/recipes/coldiron_hoe.json index 846043e6..ba775cf5 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:coldiron_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_horsearmor.json b/src/main/resources/assets/basemetals/recipes/coldiron_horsearmor.json index d8bd520f..3d0d4f41 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:coldiron_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_ingot.json b/src/main/resources/assets/basemetals/recipes/coldiron_ingot.json index 0d8d2149..f9c05442 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:coldiron_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_leggings.json b/src/main/resources/assets/basemetals/recipes/coldiron_leggings.json index 7950b02e..631189ff 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:coldiron_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/coldiron_leggings_plate_repair.json index 3785598f..e9c0ffb5 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "ColdIron", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_lever.json b/src/main/resources/assets/basemetals/recipes/coldiron_lever.json index dd1073c0..9bc69b96 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_lever.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:coldiron_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_nugget.json b/src/main/resources/assets/basemetals/recipes/coldiron_nugget.json index 15b79992..f2f67b36 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:coldiron_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_pickaxe.json b/src/main/resources/assets/basemetals/recipes/coldiron_pickaxe.json index da503e22..2925f71b 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:coldiron_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_plate.json b/src/main/resources/assets/basemetals/recipes/coldiron_plate.json index 17651c4e..fbc58e63 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_plate.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:coldiron_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_powder.json b/src/main/resources/assets/basemetals/recipes/coldiron_powder.json index 6804c3f0..08c0ffc7 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_powder.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:coldiron_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_pressureplate.json b/src/main/resources/assets/basemetals/recipes/coldiron_pressureplate.json index da569822..0b2fb597 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:coldiron_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_rod.json b/src/main/resources/assets/basemetals/recipes/coldiron_rod.json index 1ff5bcef..419946f7 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_rod.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:coldiron_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_scythe.json b/src/main/resources/assets/basemetals/recipes/coldiron_scythe.json index 42b9ec32..ba118cd6 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:coldiron_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_shears.json b/src/main/resources/assets/basemetals/recipes/coldiron_shears.json index 30f9c1f1..65e367b6 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_shears.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:coldiron_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_shield.json b/src/main/resources/assets/basemetals/recipes/coldiron_shield.json index fb840f80..dfa848c1 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_shield.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:coldiron_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/coldiron_shield_plate_repair.json index 9865dcae..fbaa6332 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "ColdIron", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_shovel.json b/src/main/resources/assets/basemetals/recipes/coldiron_shovel.json index ddb76078..4c5b9253 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:coldiron_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_slab.json b/src/main/resources/assets/basemetals/recipes/coldiron_slab.json index 4f6a2216..82eb967d 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_slab.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:coldiron_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_smallpowder.json b/src/main/resources/assets/basemetals/recipes/coldiron_smallpowder.json index 106e98f2..5ef12b3c 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:coldiron_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_stairs.json b/src/main/resources/assets/basemetals/recipes/coldiron_stairs.json index db885d4b..71f87a1c 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:coldiron_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_sword.json b/src/main/resources/assets/basemetals/recipes/coldiron_sword.json index a8b76f29..25db4030 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_sword.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:coldiron_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_trapdoor.json b/src/main/resources/assets/basemetals/recipes/coldiron_trapdoor.json index 3215ad6b..c1f6dd02 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:coldiron_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/coldiron_wall.json b/src/main/resources/assets/basemetals/recipes/coldiron_wall.json index 7b360ccc..9768326c 100644 --- a/src/main/resources/assets/basemetals/recipes/coldiron_wall.json +++ b/src/main/resources/assets/basemetals/recipes/coldiron_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:coldiron_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_arrow.json b/src/main/resources/assets/basemetals/recipes/copper_arrow.json index 43eb04b9..3ec1936f 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/copper_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:copper_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_axe.json b/src/main/resources/assets/basemetals/recipes/copper_axe.json index af87a242..8dcb1dbd 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_axe.json +++ b/src/main/resources/assets/basemetals/recipes/copper_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:copper_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_bars_1.json b/src/main/resources/assets/basemetals/recipes/copper_bars_1.json index fbe658d9..2283b895 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/copper_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:copper_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_bars_2.json b/src/main/resources/assets/basemetals/recipes/copper_bars_2.json index f22933da..3b456472 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/copper_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:copper_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_block.json b/src/main/resources/assets/basemetals/recipes/copper_block.json index c1f18a5e..39603070 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_block.json +++ b/src/main/resources/assets/basemetals/recipes/copper_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:copper_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_block_ingot.json b/src/main/resources/assets/basemetals/recipes/copper_block_ingot.json index 9bc564fd..1b8a3534 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/copper_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:copper_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:copper_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_bolt.json b/src/main/resources/assets/basemetals/recipes/copper_bolt.json index 760eee6f..81dc154a 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/copper_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:copper_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_boots.json b/src/main/resources/assets/basemetals/recipes/copper_boots.json index dfcdf7a2..043026b0 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_boots.json +++ b/src/main/resources/assets/basemetals/recipes/copper_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:copper_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/copper_boots_plate_repair.json index 107b1d4e..bf0023b2 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/copper_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Copper", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/copper_bow.json b/src/main/resources/assets/basemetals/recipes/copper_bow.json index edcd0ef6..745ae472 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_bow.json +++ b/src/main/resources/assets/basemetals/recipes/copper_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:copper_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_button.json b/src/main/resources/assets/basemetals/recipes/copper_button.json index d669b092..46343345 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_button.json +++ b/src/main/resources/assets/basemetals/recipes/copper_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:copper_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_chestplate.json b/src/main/resources/assets/basemetals/recipes/copper_chestplate.json index e2820d11..291afcdb 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/copper_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:copper_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/copper_chestplate_plate_repair.json index 93908176..b34b96c2 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/copper_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Copper", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/copper_crackhammer.json b/src/main/resources/assets/basemetals/recipes/copper_crackhammer.json index ec9f8ef5..aa6755bb 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/copper_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:copper_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_crossbow.json b/src/main/resources/assets/basemetals/recipes/copper_crossbow.json index 114005f7..8145d280 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/copper_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:copper_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_door.json b/src/main/resources/assets/basemetals/recipes/copper_door.json index 531a5ce0..611b35c9 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_door.json +++ b/src/main/resources/assets/basemetals/recipes/copper_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:copper_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_fishingrod.json b/src/main/resources/assets/basemetals/recipes/copper_fishingrod.json index 8e1c4b73..b7a0017a 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/copper_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:copper_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_gear.json b/src/main/resources/assets/basemetals/recipes/copper_gear.json index 586e8e92..05e3e185 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_gear.json +++ b/src/main/resources/assets/basemetals/recipes/copper_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:copper_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_helmet.json b/src/main/resources/assets/basemetals/recipes/copper_helmet.json index 14ca2f3b..a90fd5a9 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/copper_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:copper_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/copper_helmet_plate_repair.json index 5fe9753f..64b6a542 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/copper_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Copper", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/copper_hoe.json b/src/main/resources/assets/basemetals/recipes/copper_hoe.json index f95fccfb..1745c4cf 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/copper_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:copper_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_horsearmor.json b/src/main/resources/assets/basemetals/recipes/copper_horsearmor.json index f0cff504..67b11dfb 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/copper_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:copper_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_ingot.json b/src/main/resources/assets/basemetals/recipes/copper_ingot.json index 7b4f329b..5a4dec77 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/copper_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:copper_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_leggings.json b/src/main/resources/assets/basemetals/recipes/copper_leggings.json index c5be2b3c..1fe54611 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/copper_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:copper_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/copper_leggings_plate_repair.json index 4f75e6dd..7b56f68f 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/copper_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Copper", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/copper_lever.json b/src/main/resources/assets/basemetals/recipes/copper_lever.json index 8ec965d9..ee3baf8e 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_lever.json +++ b/src/main/resources/assets/basemetals/recipes/copper_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:copper_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_nugget.json b/src/main/resources/assets/basemetals/recipes/copper_nugget.json index 343829a4..81cf054c 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/copper_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:copper_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_pickaxe.json b/src/main/resources/assets/basemetals/recipes/copper_pickaxe.json index 19797e71..d8f9ff44 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/copper_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:copper_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_plate.json b/src/main/resources/assets/basemetals/recipes/copper_plate.json index 26c17142..233bfe85 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_plate.json +++ b/src/main/resources/assets/basemetals/recipes/copper_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:copper_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_powder.json b/src/main/resources/assets/basemetals/recipes/copper_powder.json index ac263b98..01db39cd 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_powder.json +++ b/src/main/resources/assets/basemetals/recipes/copper_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:copper_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_pressureplate.json b/src/main/resources/assets/basemetals/recipes/copper_pressureplate.json index 6375efd1..0248065a 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/copper_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:copper_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_rod.json b/src/main/resources/assets/basemetals/recipes/copper_rod.json index 65fe379d..55644e62 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_rod.json +++ b/src/main/resources/assets/basemetals/recipes/copper_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:copper_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/copper_scythe.json b/src/main/resources/assets/basemetals/recipes/copper_scythe.json index 44ab7220..dc727aaf 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/copper_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:copper_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/copper_shears.json b/src/main/resources/assets/basemetals/recipes/copper_shears.json index 7b61d91a..cd559e8f 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_shears.json +++ b/src/main/resources/assets/basemetals/recipes/copper_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:copper_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_shield.json b/src/main/resources/assets/basemetals/recipes/copper_shield.json index 903e507e..d05d310e 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_shield.json +++ b/src/main/resources/assets/basemetals/recipes/copper_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:copper_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/copper_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/copper_shield_plate_repair.json index 7b805f20..c0eadb06 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/copper_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Copper", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/copper_shovel.json b/src/main/resources/assets/basemetals/recipes/copper_shovel.json index d71f2704..4a236417 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/copper_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:copper_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_slab.json b/src/main/resources/assets/basemetals/recipes/copper_slab.json index 3310f4c1..b0ad7d79 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_slab.json +++ b/src/main/resources/assets/basemetals/recipes/copper_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:copper_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_smallpowder.json b/src/main/resources/assets/basemetals/recipes/copper_smallpowder.json index 373468a4..95436281 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/copper_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:copper_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_stairs.json b/src/main/resources/assets/basemetals/recipes/copper_stairs.json index 8e3e32fa..33dcd9f6 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/copper_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:copper_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_sword.json b/src/main/resources/assets/basemetals/recipes/copper_sword.json index 58354973..fbac7e24 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_sword.json +++ b/src/main/resources/assets/basemetals/recipes/copper_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:copper_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_trapdoor.json b/src/main/resources/assets/basemetals/recipes/copper_trapdoor.json index ab2020fc..955187d6 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/copper_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:copper_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/copper_wall.json b/src/main/resources/assets/basemetals/recipes/copper_wall.json index 7bcdf777..82d4da9c 100644 --- a/src/main/resources/assets/basemetals/recipes/copper_wall.json +++ b/src/main/resources/assets/basemetals/recipes/copper_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:copper_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_arrow.json b/src/main/resources/assets/basemetals/recipes/cupronickel_arrow.json index 886ca150..c632dac3 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:cupronickel_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_axe.json b/src/main/resources/assets/basemetals/recipes/cupronickel_axe.json index 80dbe208..9d90c6ea 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_axe.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:cupronickel_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_bars_1.json b/src/main/resources/assets/basemetals/recipes/cupronickel_bars_1.json index 28553efa..6d223200 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:cupronickel_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_bars_2.json b/src/main/resources/assets/basemetals/recipes/cupronickel_bars_2.json index 2611be7e..152ccf30 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:cupronickel_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_blend_base.json b/src/main/resources/assets/basemetals/recipes/cupronickel_blend_base.json index 4fac2253..655f2a4a 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_blend_base.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_blend_base.json @@ -23,7 +23,7 @@ "ore": "dustNickel" } ], - "group": "alloys", + "group": "basemetals:cupronickel_blend", "conditions": [ { "type": "forge:and", @@ -51,4 +51,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_blend_smallblend.json b/src/main/resources/assets/basemetals/recipes/cupronickel_blend_smallblend.json index 4e6dc173..3b726b6c 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_blend_smallblend.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_blend_smallblend.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:cupronickel_blend" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_block.json b/src/main/resources/assets/basemetals/recipes/cupronickel_block.json index 2890369a..cde978ca 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_block.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:cupronickel_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_block_ingot.json b/src/main/resources/assets/basemetals/recipes/cupronickel_block_ingot.json index 5f960bbc..69576c99 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:cupronickel_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:cupronickel_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_bolt.json b/src/main/resources/assets/basemetals/recipes/cupronickel_bolt.json index cec15ef5..d32f10fb 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:cupronickel_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_boots.json b/src/main/resources/assets/basemetals/recipes/cupronickel_boots.json index 18c7f4e2..6f74c254 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_boots.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:cupronickel_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/cupronickel_boots_plate_repair.json index 817cbcf2..3bf8f0d8 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Cupronickel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_bow.json b/src/main/resources/assets/basemetals/recipes/cupronickel_bow.json index 149c1144..bd3e7fff 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_bow.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:cupronickel_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_button.json b/src/main/resources/assets/basemetals/recipes/cupronickel_button.json index 03006738..2fe6854b 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_button.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:cupronickel_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_chestplate.json b/src/main/resources/assets/basemetals/recipes/cupronickel_chestplate.json index df56c337..a8ca3e93 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:cupronickel_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/cupronickel_chestplate_plate_repair.json index 4d5400d5..2dab1dfe 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Cupronickel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_crackhammer.json b/src/main/resources/assets/basemetals/recipes/cupronickel_crackhammer.json index 529cbf05..5cdc2f87 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:cupronickel_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_crossbow.json b/src/main/resources/assets/basemetals/recipes/cupronickel_crossbow.json index fe1ea9bd..857d6529 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:cupronickel_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_door.json b/src/main/resources/assets/basemetals/recipes/cupronickel_door.json index 891f936e..15c67cbf 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_door.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:cupronickel_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_fishingrod.json b/src/main/resources/assets/basemetals/recipes/cupronickel_fishingrod.json index 0e563c93..1da52df1 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:cupronickel_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_gear.json b/src/main/resources/assets/basemetals/recipes/cupronickel_gear.json index 866777ba..89acc2ae 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_gear.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:cupronickel_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_helmet.json b/src/main/resources/assets/basemetals/recipes/cupronickel_helmet.json index 8b4639c4..add7c1f0 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:cupronickel_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/cupronickel_helmet_plate_repair.json index 4f8fb88f..0c87f9a2 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Cupronickel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_hoe.json b/src/main/resources/assets/basemetals/recipes/cupronickel_hoe.json index f0e7d3f0..c380a9b5 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:cupronickel_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_horsearmor.json b/src/main/resources/assets/basemetals/recipes/cupronickel_horsearmor.json index 49508195..bb654863 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:cupronickel_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_ingot.json b/src/main/resources/assets/basemetals/recipes/cupronickel_ingot.json index ad460da8..28b3f424 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:cupronickel_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_leggings.json b/src/main/resources/assets/basemetals/recipes/cupronickel_leggings.json index 66cc880b..7af5693a 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:cupronickel_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/cupronickel_leggings_plate_repair.json index 0a8eda56..e047ca2e 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Cupronickel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_lever.json b/src/main/resources/assets/basemetals/recipes/cupronickel_lever.json index 4fc9c78a..53a2fe78 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_lever.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:cupronickel_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_nugget.json b/src/main/resources/assets/basemetals/recipes/cupronickel_nugget.json index cf31d8e0..c3112708 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:cupronickel_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_pickaxe.json b/src/main/resources/assets/basemetals/recipes/cupronickel_pickaxe.json index 45bd2511..de977221 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:cupronickel_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_plate.json b/src/main/resources/assets/basemetals/recipes/cupronickel_plate.json index bb49b8e2..d8e47adc 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_plate.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:cupronickel_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_powder.json b/src/main/resources/assets/basemetals/recipes/cupronickel_powder.json index 30806a48..aefce861 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_powder.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:cupronickel_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_pressureplate.json b/src/main/resources/assets/basemetals/recipes/cupronickel_pressureplate.json index 78e2ec76..7393c8a2 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:cupronickel_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_rod.json b/src/main/resources/assets/basemetals/recipes/cupronickel_rod.json index ab79e5bf..fafacabd 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_rod.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:cupronickel_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_scythe.json b/src/main/resources/assets/basemetals/recipes/cupronickel_scythe.json index 01df2461..bf283c41 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:cupronickel_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_shears.json b/src/main/resources/assets/basemetals/recipes/cupronickel_shears.json index 45b11fa3..542e9f49 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_shears.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:cupronickel_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_shield.json b/src/main/resources/assets/basemetals/recipes/cupronickel_shield.json index ea34b482..2d27ea55 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_shield.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:cupronickel_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/cupronickel_shield_plate_repair.json index e58c787a..4a23eb18 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Cupronickel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_shovel.json b/src/main/resources/assets/basemetals/recipes/cupronickel_shovel.json index 75b61f3f..043e6fdb 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:cupronickel_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_slab.json b/src/main/resources/assets/basemetals/recipes/cupronickel_slab.json index 53c25bc1..c9c096ee 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_slab.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:cupronickel_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_smallblend_blend.json b/src/main/resources/assets/basemetals/recipes/cupronickel_smallblend_blend.json index 2686f3f2..58d3d960 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_smallblend_blend.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_smallblend_blend.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:cupronickel_smallblend" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_smallpowder.json b/src/main/resources/assets/basemetals/recipes/cupronickel_smallpowder.json index de0bc88f..90a78d90 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:cupronickel_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_stairs.json b/src/main/resources/assets/basemetals/recipes/cupronickel_stairs.json index 78bdadb7..ffba3cd9 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:cupronickel_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_sword.json b/src/main/resources/assets/basemetals/recipes/cupronickel_sword.json index 3a6c6609..c5db49e4 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_sword.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:cupronickel_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_trapdoor.json b/src/main/resources/assets/basemetals/recipes/cupronickel_trapdoor.json index da1bfaf4..5658c922 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:cupronickel_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/cupronickel_wall.json b/src/main/resources/assets/basemetals/recipes/cupronickel_wall.json index 8cbc21fa..450abcdf 100644 --- a/src/main/resources/assets/basemetals/recipes/cupronickel_wall.json +++ b/src/main/resources/assets/basemetals/recipes/cupronickel_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:cupronickel_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/detector_rail.json b/src/main/resources/assets/basemetals/recipes/detector_rail.json index e7c8d33f..e19b525b 100644 --- a/src/main/resources/assets/basemetals/recipes/detector_rail.json +++ b/src/main/resources/assets/basemetals/recipes/detector_rail.json @@ -25,5 +25,5 @@ "item": "minecraft:detector_rail", "count": 6 }, - "group": "vanilla" + "group": "minecraft:detector_rail" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_arrow.json b/src/main/resources/assets/basemetals/recipes/diamond_arrow.json index 0a887dd0..0fed41e3 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_arrow" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_bars_1.json b/src/main/resources/assets/basemetals/recipes/diamond_bars_1.json index 8f84fdbf..99177abd 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_bars" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_bars_2.json b/src/main/resources/assets/basemetals/recipes/diamond_bars_2.json index e44e0488..b253b857 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_bars" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_bolt.json b/src/main/resources/assets/basemetals/recipes/diamond_bolt.json index ae9e23fc..0309d642 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_bolt.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_bolt" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/diamond_boots_plate_repair.json index 434f6a2e..1a9f3f34 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Diamond", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/diamond_bow.json b/src/main/resources/assets/basemetals/recipes/diamond_bow.json index 79b65fef..90ed5147 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_bow.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_bow" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_button.json b/src/main/resources/assets/basemetals/recipes/diamond_button.json index a128d7cf..1f15284b 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_button.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_button" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/diamond_chestplate_plate_repair.json index 8e12c020..d02dbf37 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Diamond", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/diamond_crackhammer.json b/src/main/resources/assets/basemetals/recipes/diamond_crackhammer.json index 556e120f..976c5b52 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_crackhammer" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_crossbow.json b/src/main/resources/assets/basemetals/recipes/diamond_crossbow.json index c15d738e..9d8a555c 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_crossbow" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_door.json b/src/main/resources/assets/basemetals/recipes/diamond_door.json index e14da20a..9595a0d4 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_door.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_door" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_fishingrod.json b/src/main/resources/assets/basemetals/recipes/diamond_fishingrod.json index 06eefbba..85ce5a08 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_fishing_rod" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_gear.json b/src/main/resources/assets/basemetals/recipes/diamond_gear.json index 07c41305..bf92eab3 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_gear.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "vanilla" + "group": "basemetals:diamond_gear" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/diamond_helmet_plate_repair.json index 928f3968..736bdd68 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Diamond", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/diamond_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/diamond_leggings_plate_repair.json index 8b53a8c6..27eefffe 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Diamond", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/diamond_lever.json b/src/main/resources/assets/basemetals/recipes/diamond_lever.json index 6e1a4644..e24ad2d8 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_lever.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_lever" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_powder.json b/src/main/resources/assets/basemetals/recipes/diamond_powder.json index 6cf1f8fb..94d5dd0c 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_powder.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_powder" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_pressureplate.json b/src/main/resources/assets/basemetals/recipes/diamond_pressureplate.json index 450785be..2fa7a53d 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_pressure_plate" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_rod.json b/src/main/resources/assets/basemetals/recipes/diamond_rod.json index e5a8fad6..576f585a 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_rod.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:diamond_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/diamond_scythe.json b/src/main/resources/assets/basemetals/recipes/diamond_scythe.json index 23c6ce19..60d426f1 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:diamond_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_shears.json b/src/main/resources/assets/basemetals/recipes/diamond_shears.json index d3d96040..c40270e6 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_shears.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_shears" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_shield.json b/src/main/resources/assets/basemetals/recipes/diamond_shield.json index 33c01103..8fe39a17 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_shield.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/diamond_shield_plate_repair.json index 9ac807b7..790373d0 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Diamond", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/diamond_slab.json b/src/main/resources/assets/basemetals/recipes/diamond_slab.json index a9936776..36eee526 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_slab.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_slab" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_smallpowder.json b/src/main/resources/assets/basemetals/recipes/diamond_smallpowder.json index d8dd6695..e73e840e 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_smallpowder" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_stairs.json b/src/main/resources/assets/basemetals/recipes/diamond_stairs.json index ca791bf6..5a21433e 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_stairs" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_trapdoor.json b/src/main/resources/assets/basemetals/recipes/diamond_trapdoor.json index f1c596ab..4fe99559 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_trapdoor" } diff --git a/src/main/resources/assets/basemetals/recipes/diamond_wall.json b/src/main/resources/assets/basemetals/recipes/diamond_wall.json index 685b5d3e..2fe5a5d0 100644 --- a/src/main/resources/assets/basemetals/recipes/diamond_wall.json +++ b/src/main/resources/assets/basemetals/recipes/diamond_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:diamond_wall" } diff --git a/src/main/resources/assets/basemetals/recipes/electrum_arrow.json b/src/main/resources/assets/basemetals/recipes/electrum_arrow.json index 43737f3a..2e11ab4e 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:electrum_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_axe.json b/src/main/resources/assets/basemetals/recipes/electrum_axe.json index 58939bcb..43df2399 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_axe.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:electrum_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_bars_1.json b/src/main/resources/assets/basemetals/recipes/electrum_bars_1.json index f0084e1e..4ebf1e97 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:electrum_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_bars_2.json b/src/main/resources/assets/basemetals/recipes/electrum_bars_2.json index 73001c81..082aaf12 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:electrum_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_blend_base.json b/src/main/resources/assets/basemetals/recipes/electrum_blend_base.json index 462a0603..7b49bda1 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_blend_base.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_blend_base.json @@ -15,7 +15,7 @@ "ore": "dustSilver" } ], - "group": "alloys", + "group": "basemetals:electrum_blend", "conditions": [ { "type": "forge:and", @@ -38,4 +38,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_blend_smallblend.json b/src/main/resources/assets/basemetals/recipes/electrum_blend_smallblend.json index e3d9ac55..e2ae2de6 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_blend_smallblend.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_blend_smallblend.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:electrum_blend" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_block.json b/src/main/resources/assets/basemetals/recipes/electrum_block.json index 2e129453..09d6b12c 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_block.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:electrum_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_block_ingot.json b/src/main/resources/assets/basemetals/recipes/electrum_block_ingot.json index 1ade93f8..153403d9 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:electrum_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:electrum_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_bolt.json b/src/main/resources/assets/basemetals/recipes/electrum_bolt.json index b60e4072..51543717 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:electrum_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_boots.json b/src/main/resources/assets/basemetals/recipes/electrum_boots.json index 1d0674c2..891ddf63 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_boots.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:electrum_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/electrum_boots_plate_repair.json index 273b6bf9..c7a6d0b1 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Electrum", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/electrum_bow.json b/src/main/resources/assets/basemetals/recipes/electrum_bow.json index bb6fe7b9..1b4fe1e1 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_bow.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:electrum_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_button.json b/src/main/resources/assets/basemetals/recipes/electrum_button.json index 078a8e1b..249e2e1b 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_button.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:electrum_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_chestplate.json b/src/main/resources/assets/basemetals/recipes/electrum_chestplate.json index 7cde4d25..dd3a42d2 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:electrum_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/electrum_chestplate_plate_repair.json index bfd8524a..c4179cec 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Electrum", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/electrum_crackhammer.json b/src/main/resources/assets/basemetals/recipes/electrum_crackhammer.json index 7ce0e0b1..b278b439 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:electrum_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_crossbow.json b/src/main/resources/assets/basemetals/recipes/electrum_crossbow.json index 2337d5e9..2f9e74a6 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:electrum_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_door.json b/src/main/resources/assets/basemetals/recipes/electrum_door.json index df072d94..ce1966e7 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_door.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:electrum_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_fishingrod.json b/src/main/resources/assets/basemetals/recipes/electrum_fishingrod.json index 424ea205..213891c5 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:electrum_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_gear.json b/src/main/resources/assets/basemetals/recipes/electrum_gear.json index 97be9683..bc983d75 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_gear.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:electrum_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_helmet.json b/src/main/resources/assets/basemetals/recipes/electrum_helmet.json index 29164903..a07fbde5 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:electrum_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/electrum_helmet_plate_repair.json index a47e0b65..97b835de 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Electrum", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/electrum_hoe.json b/src/main/resources/assets/basemetals/recipes/electrum_hoe.json index 2940b918..472001dc 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:electrum_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_horsearmor.json b/src/main/resources/assets/basemetals/recipes/electrum_horsearmor.json index b62d3c05..53d6bb6c 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:electrum_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_ingot.json b/src/main/resources/assets/basemetals/recipes/electrum_ingot.json index e67b6c8b..95082620 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:electrum_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_leggings.json b/src/main/resources/assets/basemetals/recipes/electrum_leggings.json index 2dc9ae4f..6104fa5a 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:electrum_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/electrum_leggings_plate_repair.json index 30983122..ec937b23 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Electrum", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/electrum_lever.json b/src/main/resources/assets/basemetals/recipes/electrum_lever.json index 72002310..22e98a3a 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_lever.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:electrum_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_nugget.json b/src/main/resources/assets/basemetals/recipes/electrum_nugget.json index c2fdf4a3..677a1488 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:electrum_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_pickaxe.json b/src/main/resources/assets/basemetals/recipes/electrum_pickaxe.json index ea82c01e..82aa813f 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:electrum_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_plate.json b/src/main/resources/assets/basemetals/recipes/electrum_plate.json index ee923ca6..9eab4f20 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_plate.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:electrum_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_powder.json b/src/main/resources/assets/basemetals/recipes/electrum_powder.json index d7c4344f..0e58b69f 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_powder.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:electrum_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_pressureplate.json b/src/main/resources/assets/basemetals/recipes/electrum_pressureplate.json index 74b56ae0..6fc8df20 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:electrum_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_rod.json b/src/main/resources/assets/basemetals/recipes/electrum_rod.json index b08af7a8..203e8bcd 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_rod.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:electrum_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/electrum_scythe.json b/src/main/resources/assets/basemetals/recipes/electrum_scythe.json index a1b0ce4f..1c90a5f2 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:electrum_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/electrum_shears.json b/src/main/resources/assets/basemetals/recipes/electrum_shears.json index bc98a87d..787fb5bd 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_shears.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:electrum_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_shield.json b/src/main/resources/assets/basemetals/recipes/electrum_shield.json index d4eb504b..67b8b472 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_shield.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:electrum_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/electrum_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/electrum_shield_plate_repair.json index 98039353..552f1a65 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Electrum", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/electrum_shovel.json b/src/main/resources/assets/basemetals/recipes/electrum_shovel.json index 92b7995d..77627165 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:electrum_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_slab.json b/src/main/resources/assets/basemetals/recipes/electrum_slab.json index 72091e7f..952445b1 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_slab.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:electrum_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_smallblend_blend.json b/src/main/resources/assets/basemetals/recipes/electrum_smallblend_blend.json index 9df909fd..d5cc635e 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_smallblend_blend.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_smallblend_blend.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:electrum_smallblend" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_smallpowder.json b/src/main/resources/assets/basemetals/recipes/electrum_smallpowder.json index 4c2765d4..b4a28cff 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:electrum_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_stairs.json b/src/main/resources/assets/basemetals/recipes/electrum_stairs.json index efb93905..62ea0eac 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:electrum_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_sword.json b/src/main/resources/assets/basemetals/recipes/electrum_sword.json index b425671b..6bc10bff 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_sword.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:electrum_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_trapdoor.json b/src/main/resources/assets/basemetals/recipes/electrum_trapdoor.json index ff547496..bbd9a2b8 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:electrum_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/electrum_wall.json b/src/main/resources/assets/basemetals/recipes/electrum_wall.json index 7c976fb8..8e03397d 100644 --- a/src/main/resources/assets/basemetals/recipes/electrum_wall.json +++ b/src/main/resources/assets/basemetals/recipes/electrum_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:electrum_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/emerald_arrow.json b/src/main/resources/assets/basemetals/recipes/emerald_arrow.json index 58936fdc..4b2f3b6d 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_arrow" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_axe.json b/src/main/resources/assets/basemetals/recipes/emerald_axe.json index 7fd893b8..be56c613 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_axe.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_axe" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_bars_1.json b/src/main/resources/assets/basemetals/recipes/emerald_bars_1.json index 0779b1d6..d75cd8d9 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_bars" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_bars_2.json b/src/main/resources/assets/basemetals/recipes/emerald_bars_2.json index 072c2fc6..167494ff 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_bars" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_bolt.json b/src/main/resources/assets/basemetals/recipes/emerald_bolt.json index b0107d90..33a4579b 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_bolt.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_bolt" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_boots.json b/src/main/resources/assets/basemetals/recipes/emerald_boots.json index e0aee781..8616e7d6 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_boots.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_boots" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/emerald_boots_plate_repair.json index deea2260..27a7c48e 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Emerald", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/emerald_bow.json b/src/main/resources/assets/basemetals/recipes/emerald_bow.json index 53695fc2..04b8d02b 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_bow.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_bow" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_button.json b/src/main/resources/assets/basemetals/recipes/emerald_button.json index 5676547b..b2e219d0 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_button.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_button" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_chestplate.json b/src/main/resources/assets/basemetals/recipes/emerald_chestplate.json index b51414ff..e6728f06 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_chestplate" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/emerald_chestplate_plate_repair.json index 02f28d40..6b567401 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Emerald", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/emerald_crackhammer.json b/src/main/resources/assets/basemetals/recipes/emerald_crackhammer.json index 8ef6cb06..701a30b6 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_crackhammer" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_crossbow.json b/src/main/resources/assets/basemetals/recipes/emerald_crossbow.json index 62ede77a..280cb44a 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_crossbow" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_door.json b/src/main/resources/assets/basemetals/recipes/emerald_door.json index d614a11b..c0f0cafe 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_door.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_door" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_fishingrod.json b/src/main/resources/assets/basemetals/recipes/emerald_fishingrod.json index 3681be38..4f116b63 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_fishing_rod" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_gear.json b/src/main/resources/assets/basemetals/recipes/emerald_gear.json index c4525c13..7c270700 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_gear.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "vanilla" + "group": "basemetals:emerald_gear" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_helmet.json b/src/main/resources/assets/basemetals/recipes/emerald_helmet.json index 459ac51d..8ec330e1 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_helmet" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/emerald_helmet_plate_repair.json index 90615ff4..45270c92 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Emerald", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/emerald_hoe.json b/src/main/resources/assets/basemetals/recipes/emerald_hoe.json index 20a7fe0f..9608a17a 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_hoe" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_horsearmor.json b/src/main/resources/assets/basemetals/recipes/emerald_horsearmor.json index 75733728..787576b2 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:emerald_horse_armor" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_leggings.json b/src/main/resources/assets/basemetals/recipes/emerald_leggings.json index fd0f53fe..9d3eb0cf 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_leggings" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/emerald_leggings_plate_repair.json index 40635247..0a088a55 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Emerald", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/emerald_lever.json b/src/main/resources/assets/basemetals/recipes/emerald_lever.json index c074ab09..5b6e95d3 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_lever.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_lever" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_pickaxe.json b/src/main/resources/assets/basemetals/recipes/emerald_pickaxe.json index 13bd22e3..6adf703b 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_pickaxe" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_powder.json b/src/main/resources/assets/basemetals/recipes/emerald_powder.json index 13583a21..fd9737ec 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_powder.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_powder" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_pressureplate.json b/src/main/resources/assets/basemetals/recipes/emerald_pressureplate.json index 9a42abac..3dac3a39 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_pressure_plate" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_rod.json b/src/main/resources/assets/basemetals/recipes/emerald_rod.json index d966db12..0630eaa5 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_rod.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:emerald_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/emerald_scythe.json b/src/main/resources/assets/basemetals/recipes/emerald_scythe.json index 109002b9..f1ab0603 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:emerald_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_shears.json b/src/main/resources/assets/basemetals/recipes/emerald_shears.json index 4c3e4030..82d384b3 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_shears.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_shears" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_shield.json b/src/main/resources/assets/basemetals/recipes/emerald_shield.json index f7ad15e3..e47b2174 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_shield.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/emerald_shield_plate_repair.json index c25af9d5..67a67bbc 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Emerald", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/emerald_shovel.json b/src/main/resources/assets/basemetals/recipes/emerald_shovel.json index ffe80cc1..c9a74d9b 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_shovel" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_slab.json b/src/main/resources/assets/basemetals/recipes/emerald_slab.json index 09b2b99f..a65722e9 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_slab.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_slab" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_smallpowder.json b/src/main/resources/assets/basemetals/recipes/emerald_smallpowder.json index f89afea7..ca24c797 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_smallpowder" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_stairs.json b/src/main/resources/assets/basemetals/recipes/emerald_stairs.json index 2ab4125d..5c237c76 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_stairs" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_sword.json b/src/main/resources/assets/basemetals/recipes/emerald_sword.json index 2e6adf96..ffc73a66 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_sword.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_sword.json @@ -40,5 +40,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_sword" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_trapdoor.json b/src/main/resources/assets/basemetals/recipes/emerald_trapdoor.json index 67d29c86..99c53dfc 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_trapdoor" } diff --git a/src/main/resources/assets/basemetals/recipes/emerald_wall.json b/src/main/resources/assets/basemetals/recipes/emerald_wall.json index 228a8cb7..292b32a2 100644 --- a/src/main/resources/assets/basemetals/recipes/emerald_wall.json +++ b/src/main/resources/assets/basemetals/recipes/emerald_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:emerald_wall" } diff --git a/src/main/resources/assets/basemetals/recipes/flint_and_steel.json b/src/main/resources/assets/basemetals/recipes/flint_and_steel.json index 6715736b..52645051 100644 --- a/src/main/resources/assets/basemetals/recipes/flint_and_steel.json +++ b/src/main/resources/assets/basemetals/recipes/flint_and_steel.json @@ -17,5 +17,5 @@ "result": { "item": "minecraft:flint_and_steel" }, - "group": "vanilla" + "group": "minecraft:flint_and_steel" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_arrow.json b/src/main/resources/assets/basemetals/recipes/gold_arrow.json index 9d27d869..2a5ae1d9 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/gold_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_arrow" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_bars_1.json b/src/main/resources/assets/basemetals/recipes/gold_bars_1.json index 2521e4d0..6a163388 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/gold_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_bars" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_bars_2.json b/src/main/resources/assets/basemetals/recipes/gold_bars_2.json index d1700523..55c781d8 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/gold_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_bars" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_bolt.json b/src/main/resources/assets/basemetals/recipes/gold_bolt.json index 94002b44..e2d46050 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/gold_bolt.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_bolt" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/gold_boots_plate_repair.json index 9a66e765..903d2a44 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/gold_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Gold", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/gold_bow.json b/src/main/resources/assets/basemetals/recipes/gold_bow.json index bd408eaa..7c9b8ac3 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_bow.json +++ b/src/main/resources/assets/basemetals/recipes/gold_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_bow" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_button.json b/src/main/resources/assets/basemetals/recipes/gold_button.json index 11a1921c..489c255f 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_button.json +++ b/src/main/resources/assets/basemetals/recipes/gold_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_button" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/gold_chestplate_plate_repair.json index d02cde57..18c418e5 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/gold_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Gold", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/gold_crackhammer.json b/src/main/resources/assets/basemetals/recipes/gold_crackhammer.json index 6f6ce29e..35cb666a 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/gold_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_crackhammer" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_crossbow.json b/src/main/resources/assets/basemetals/recipes/gold_crossbow.json index 20547b31..0a1c8ddf 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/gold_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_crossbow" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_door.json b/src/main/resources/assets/basemetals/recipes/gold_door.json index 2f03b039..06955fa6 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_door.json +++ b/src/main/resources/assets/basemetals/recipes/gold_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_door" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_fishingrod.json b/src/main/resources/assets/basemetals/recipes/gold_fishingrod.json index 7db00868..398e34e0 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/gold_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_fishing_rod" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_gear.json b/src/main/resources/assets/basemetals/recipes/gold_gear.json index 18ca4259..a7b1f85d 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_gear.json +++ b/src/main/resources/assets/basemetals/recipes/gold_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "vanilla" + "group": "basemetals:gold_gear" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/gold_helmet_plate_repair.json index b7f3c6a9..da3fb47e 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/gold_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Gold", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/gold_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/gold_leggings_plate_repair.json index 7c2d455b..4bcbdd3a 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/gold_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Gold", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/gold_lever.json b/src/main/resources/assets/basemetals/recipes/gold_lever.json index 9ad2a42d..c5b04cd6 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_lever.json +++ b/src/main/resources/assets/basemetals/recipes/gold_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_lever" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_plate.json b/src/main/resources/assets/basemetals/recipes/gold_plate.json index 6709cdb8..80e64bb3 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_plate.json +++ b/src/main/resources/assets/basemetals/recipes/gold_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "vanilla" + "group": "basemetals:gold_plate" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_powder.json b/src/main/resources/assets/basemetals/recipes/gold_powder.json index 1da2b3ad..cf5dfac1 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_powder.json +++ b/src/main/resources/assets/basemetals/recipes/gold_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_powder" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_rod.json b/src/main/resources/assets/basemetals/recipes/gold_rod.json index 20cb560d..04fc79fa 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_rod.json +++ b/src/main/resources/assets/basemetals/recipes/gold_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:gold_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/gold_scythe.json b/src/main/resources/assets/basemetals/recipes/gold_scythe.json index ecbe1a93..2ad2f5aa 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/gold_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:gold_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_shears.json b/src/main/resources/assets/basemetals/recipes/gold_shears.json index c41fef0c..48822a99 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_shears.json +++ b/src/main/resources/assets/basemetals/recipes/gold_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_shears" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_shield.json b/src/main/resources/assets/basemetals/recipes/gold_shield.json index 4b91377a..8095c076 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_shield.json +++ b/src/main/resources/assets/basemetals/recipes/gold_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/gold_shield_plate_repair.json index 349a3413..11852886 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/gold_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Gold", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/gold_slab.json b/src/main/resources/assets/basemetals/recipes/gold_slab.json index c1668335..9b3a9899 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_slab.json +++ b/src/main/resources/assets/basemetals/recipes/gold_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_slab" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_smallpowder.json b/src/main/resources/assets/basemetals/recipes/gold_smallpowder.json index 3f90238e..36a03551 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/gold_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_smallpowder" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_stairs.json b/src/main/resources/assets/basemetals/recipes/gold_stairs.json index b00a7d19..c7917df8 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/gold_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_stairs" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_trapdoor.json b/src/main/resources/assets/basemetals/recipes/gold_trapdoor.json index 96437602..d4410ad9 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/gold_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_trapdoor" } diff --git a/src/main/resources/assets/basemetals/recipes/gold_wall.json b/src/main/resources/assets/basemetals/recipes/gold_wall.json index 79bbc6c1..dd77b036 100644 --- a/src/main/resources/assets/basemetals/recipes/gold_wall.json +++ b/src/main/resources/assets/basemetals/recipes/gold_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:gold_wall" } diff --git a/src/main/resources/assets/basemetals/recipes/human_detector.json b/src/main/resources/assets/basemetals/recipes/human_detector.json index 1103fb09..45bde5e8 100644 --- a/src/main/resources/assets/basemetals/recipes/human_detector.json +++ b/src/main/resources/assets/basemetals/recipes/human_detector.json @@ -20,5 +20,5 @@ "result": { "item": "basemetals:human_detector" }, - "group": "vanilla" + "group": "basemetals:human_detector" } diff --git a/src/main/resources/assets/basemetals/recipes/invar_arrow.json b/src/main/resources/assets/basemetals/recipes/invar_arrow.json index 83beb889..906a628d 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/invar_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:invar_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_axe.json b/src/main/resources/assets/basemetals/recipes/invar_axe.json index ca9d6ba8..910f08bc 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_axe.json +++ b/src/main/resources/assets/basemetals/recipes/invar_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:invar_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_bars_1.json b/src/main/resources/assets/basemetals/recipes/invar_bars_1.json index 347896d8..2d61c4a1 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/invar_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:invar_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_bars_2.json b/src/main/resources/assets/basemetals/recipes/invar_bars_2.json index 8dcbe625..db283b70 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/invar_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:invar_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_blend_base.json b/src/main/resources/assets/basemetals/recipes/invar_blend_base.json index 1c4bc0de..3260c5cc 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_blend_base.json +++ b/src/main/resources/assets/basemetals/recipes/invar_blend_base.json @@ -19,7 +19,7 @@ "ore": "dustNickel" } ], - "group": "alloys", + "group": "basemetals:invar_blend", "conditions": [ { "type": "forge:and", @@ -47,4 +47,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_blend_smallblend.json b/src/main/resources/assets/basemetals/recipes/invar_blend_smallblend.json index 2001fb85..1f50775c 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_blend_smallblend.json +++ b/src/main/resources/assets/basemetals/recipes/invar_blend_smallblend.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:invar_blend" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_block.json b/src/main/resources/assets/basemetals/recipes/invar_block.json index 88785e18..56f26949 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_block.json +++ b/src/main/resources/assets/basemetals/recipes/invar_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:invar_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_block_ingot.json b/src/main/resources/assets/basemetals/recipes/invar_block_ingot.json index 8fcd993c..dad3ca9c 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/invar_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:invar_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:invar_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_bolt.json b/src/main/resources/assets/basemetals/recipes/invar_bolt.json index a52c1292..cbff5a07 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/invar_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:invar_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_boots.json b/src/main/resources/assets/basemetals/recipes/invar_boots.json index 791aa1e9..eca97a90 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_boots.json +++ b/src/main/resources/assets/basemetals/recipes/invar_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:invar_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_bow.json b/src/main/resources/assets/basemetals/recipes/invar_bow.json index d030e13a..374fe452 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_bow.json +++ b/src/main/resources/assets/basemetals/recipes/invar_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:invar_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_button.json b/src/main/resources/assets/basemetals/recipes/invar_button.json index be8e8f0f..1c071373 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_button.json +++ b/src/main/resources/assets/basemetals/recipes/invar_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:invar_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_chestplate.json b/src/main/resources/assets/basemetals/recipes/invar_chestplate.json index 2660d4eb..38a7287c 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/invar_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:invar_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_crackhammer.json b/src/main/resources/assets/basemetals/recipes/invar_crackhammer.json index 559e0b9a..c3bd577b 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/invar_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:invar_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_crossbow.json b/src/main/resources/assets/basemetals/recipes/invar_crossbow.json index 00ca98f0..21904855 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/invar_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:invar_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_door.json b/src/main/resources/assets/basemetals/recipes/invar_door.json index 59e87ddb..8c7791c2 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_door.json +++ b/src/main/resources/assets/basemetals/recipes/invar_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:invar_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_fishingrod.json b/src/main/resources/assets/basemetals/recipes/invar_fishingrod.json index 93735fba..4e81c0e7 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/invar_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:invar_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_gear.json b/src/main/resources/assets/basemetals/recipes/invar_gear.json index 72a624b7..d0726183 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_gear.json +++ b/src/main/resources/assets/basemetals/recipes/invar_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:invar_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_helmet.json b/src/main/resources/assets/basemetals/recipes/invar_helmet.json index 1183d06d..1db8641d 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/invar_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:invar_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_hoe.json b/src/main/resources/assets/basemetals/recipes/invar_hoe.json index 7c26feab..dde8be4d 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/invar_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:invar_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_horsearmor.json b/src/main/resources/assets/basemetals/recipes/invar_horsearmor.json index 47d07445..dcfd0769 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/invar_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:invar_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_ingot.json b/src/main/resources/assets/basemetals/recipes/invar_ingot.json index 928cdb18..50b4cb2f 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/invar_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:invar_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_leggings.json b/src/main/resources/assets/basemetals/recipes/invar_leggings.json index ce3ebafd..93e1782e 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/invar_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:invar_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_lever.json b/src/main/resources/assets/basemetals/recipes/invar_lever.json index 35f3cad7..b6571a55 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_lever.json +++ b/src/main/resources/assets/basemetals/recipes/invar_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:invar_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_nugget.json b/src/main/resources/assets/basemetals/recipes/invar_nugget.json index 846a0b17..e148f7c6 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/invar_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:invar_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_pickaxe.json b/src/main/resources/assets/basemetals/recipes/invar_pickaxe.json index 0c5ec1c1..0573db94 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/invar_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:invar_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_plate.json b/src/main/resources/assets/basemetals/recipes/invar_plate.json index 6dd8d19d..05a9792b 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_plate.json +++ b/src/main/resources/assets/basemetals/recipes/invar_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:invar_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_powder.json b/src/main/resources/assets/basemetals/recipes/invar_powder.json index 44ad3b84..f889f6d2 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_powder.json +++ b/src/main/resources/assets/basemetals/recipes/invar_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:invar_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_pressureplate.json b/src/main/resources/assets/basemetals/recipes/invar_pressureplate.json index 038dca91..dfbeb6dc 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/invar_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:invar_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_rod.json b/src/main/resources/assets/basemetals/recipes/invar_rod.json index 5ed03c1a..3d6fbf7d 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_rod.json +++ b/src/main/resources/assets/basemetals/recipes/invar_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:invar_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/invar_scythe.json b/src/main/resources/assets/basemetals/recipes/invar_scythe.json index f7bb9327..ba82ba7e 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/invar_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:invar_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/invar_shears.json b/src/main/resources/assets/basemetals/recipes/invar_shears.json index 384c3d1d..037c34f0 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_shears.json +++ b/src/main/resources/assets/basemetals/recipes/invar_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:invar_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_shield.json b/src/main/resources/assets/basemetals/recipes/invar_shield.json index aa6b39d1..c140b91c 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_shield.json +++ b/src/main/resources/assets/basemetals/recipes/invar_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:invar_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/invar_shovel.json b/src/main/resources/assets/basemetals/recipes/invar_shovel.json index 144d769b..c5b7f11c 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/invar_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:invar_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_slab.json b/src/main/resources/assets/basemetals/recipes/invar_slab.json index 223ca94a..ecf691d8 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_slab.json +++ b/src/main/resources/assets/basemetals/recipes/invar_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:invar_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_smallblend_blend.json b/src/main/resources/assets/basemetals/recipes/invar_smallblend_blend.json index 97a58d79..95b9d109 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_smallblend_blend.json +++ b/src/main/resources/assets/basemetals/recipes/invar_smallblend_blend.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:invar_smallblend" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_smallpowder.json b/src/main/resources/assets/basemetals/recipes/invar_smallpowder.json index d98192eb..391e47a2 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/invar_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:invar_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_stairs.json b/src/main/resources/assets/basemetals/recipes/invar_stairs.json index 084c7111..fc8fc740 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/invar_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:invar_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_sword.json b/src/main/resources/assets/basemetals/recipes/invar_sword.json index b3fd6d46..ec31a3c2 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_sword.json +++ b/src/main/resources/assets/basemetals/recipes/invar_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:invar_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_trapdoor.json b/src/main/resources/assets/basemetals/recipes/invar_trapdoor.json index c37f63da..601d941f 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/invar_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:invar_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/invar_wall.json b/src/main/resources/assets/basemetals/recipes/invar_wall.json index 25dd0a55..ca08976a 100644 --- a/src/main/resources/assets/basemetals/recipes/invar_wall.json +++ b/src/main/resources/assets/basemetals/recipes/invar_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:invar_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/iron_arrow.json b/src/main/resources/assets/basemetals/recipes/iron_arrow.json index b8321a7a..e070fd17 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/iron_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:iron_arrow" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_bars_2.json b/src/main/resources/assets/basemetals/recipes/iron_bars_2.json index 355f02e3..ad2cdcaa 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/iron_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "minecraft:iron_bars" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_bolt.json b/src/main/resources/assets/basemetals/recipes/iron_bolt.json index db3a438c..386a6be3 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/iron_bolt.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:iron_bolt" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/iron_boots_plate_repair.json index 4492e22d..f020fc18 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/iron_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Iron", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/iron_bow.json b/src/main/resources/assets/basemetals/recipes/iron_bow.json index c4a8eafa..7ccb509f 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_bow.json +++ b/src/main/resources/assets/basemetals/recipes/iron_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:iron_bow" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_button.json b/src/main/resources/assets/basemetals/recipes/iron_button.json index e95cb741..2df85f52 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_button.json +++ b/src/main/resources/assets/basemetals/recipes/iron_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:iron_button" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/iron_chestplate_plate_repair.json index 0745069a..2f7c2fa2 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/iron_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Iron", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/iron_crackhammer.json b/src/main/resources/assets/basemetals/recipes/iron_crackhammer.json index 85de1a87..81fefb56 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/iron_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:iron_crackhammer" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_crossbow.json b/src/main/resources/assets/basemetals/recipes/iron_crossbow.json index 4defbba4..07296129 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/iron_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:iron_crossbow" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_fishingrod.json b/src/main/resources/assets/basemetals/recipes/iron_fishingrod.json index 236d6064..a108107b 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/iron_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:iron_fishing_rod" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_gear.json b/src/main/resources/assets/basemetals/recipes/iron_gear.json index 5f5b4a01..466c3fbf 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_gear.json +++ b/src/main/resources/assets/basemetals/recipes/iron_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "vanilla" + "group": "basemetals:iron_gear" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/iron_helmet_plate_repair.json index 8c2443af..db972148 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/iron_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Iron", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/iron_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/iron_leggings_plate_repair.json index d717b4d8..d580a0d3 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/iron_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Iron", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/iron_lever.json b/src/main/resources/assets/basemetals/recipes/iron_lever.json index b09bc28d..bb49bee0 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_lever.json +++ b/src/main/resources/assets/basemetals/recipes/iron_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:iron_lever" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_plate.json b/src/main/resources/assets/basemetals/recipes/iron_plate.json index e679e58b..435adab1 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_plate.json +++ b/src/main/resources/assets/basemetals/recipes/iron_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "vanilla" + "group": "basemetals:iron_plate" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_powder.json b/src/main/resources/assets/basemetals/recipes/iron_powder.json index e2eee40b..3be472a9 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_powder.json +++ b/src/main/resources/assets/basemetals/recipes/iron_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:iron_powder" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_rod.json b/src/main/resources/assets/basemetals/recipes/iron_rod.json index 8a368059..3b7c07ce 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_rod.json +++ b/src/main/resources/assets/basemetals/recipes/iron_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:iron_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/iron_scythe.json b/src/main/resources/assets/basemetals/recipes/iron_scythe.json index 1fc850ac..bd72b2e4 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/iron_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:iron_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_shield.json b/src/main/resources/assets/basemetals/recipes/iron_shield.json index f1c36801..487edd66 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_shield.json +++ b/src/main/resources/assets/basemetals/recipes/iron_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:iron_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/iron_shield_plate_repair.json index 62f403eb..4fa2f98c 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/iron_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Iron", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/iron_slab.json b/src/main/resources/assets/basemetals/recipes/iron_slab.json index c67cb2a9..1a113ec9 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_slab.json +++ b/src/main/resources/assets/basemetals/recipes/iron_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:iron_slab" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_smallpowder.json b/src/main/resources/assets/basemetals/recipes/iron_smallpowder.json index 144c14e7..c1477388 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/iron_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:iron_smallpowder" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_stairs.json b/src/main/resources/assets/basemetals/recipes/iron_stairs.json index 799ed0df..42f7d12a 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/iron_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:iron_stairs" } diff --git a/src/main/resources/assets/basemetals/recipes/iron_wall.json b/src/main/resources/assets/basemetals/recipes/iron_wall.json index 5bccb352..1949fc3d 100644 --- a/src/main/resources/assets/basemetals/recipes/iron_wall.json +++ b/src/main/resources/assets/basemetals/recipes/iron_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:iron_wall" } diff --git a/src/main/resources/assets/basemetals/recipes/lead_arrow.json b/src/main/resources/assets/basemetals/recipes/lead_arrow.json index 0cd28fb2..7ba71d55 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/lead_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:lead_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_axe.json b/src/main/resources/assets/basemetals/recipes/lead_axe.json index 8076777e..793bcd02 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_axe.json +++ b/src/main/resources/assets/basemetals/recipes/lead_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:lead_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_bars_1.json b/src/main/resources/assets/basemetals/recipes/lead_bars_1.json index 8c45a148..0e77216b 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/lead_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:lead_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_bars_2.json b/src/main/resources/assets/basemetals/recipes/lead_bars_2.json index 2781bd56..d99d9f78 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/lead_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:lead_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_block.json b/src/main/resources/assets/basemetals/recipes/lead_block.json index 49f4dc8c..ed9d9e90 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_block.json +++ b/src/main/resources/assets/basemetals/recipes/lead_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:lead_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_block_ingot.json b/src/main/resources/assets/basemetals/recipes/lead_block_ingot.json index 8770f3eb..d1e88b7c 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/lead_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:lead_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:lead_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_bolt.json b/src/main/resources/assets/basemetals/recipes/lead_bolt.json index af73dce1..7bc74152 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/lead_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:lead_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_boots.json b/src/main/resources/assets/basemetals/recipes/lead_boots.json index dbf88255..c16b7294 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_boots.json +++ b/src/main/resources/assets/basemetals/recipes/lead_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:lead_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/lead_boots_plate_repair.json index 976361d9..01d9458c 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/lead_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Lead", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/lead_bow.json b/src/main/resources/assets/basemetals/recipes/lead_bow.json index c6266e22..dea1c0c3 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_bow.json +++ b/src/main/resources/assets/basemetals/recipes/lead_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:lead_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_button.json b/src/main/resources/assets/basemetals/recipes/lead_button.json index fcbf1a67..113b725b 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_button.json +++ b/src/main/resources/assets/basemetals/recipes/lead_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:lead_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_chestplate.json b/src/main/resources/assets/basemetals/recipes/lead_chestplate.json index b9bb5617..6c063ad3 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/lead_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:lead_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/lead_chestplate_plate_repair.json index 1f5a2838..a6f13c06 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/lead_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Lead", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/lead_crackhammer.json b/src/main/resources/assets/basemetals/recipes/lead_crackhammer.json index 3bdce914..90ec0208 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/lead_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:lead_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_crossbow.json b/src/main/resources/assets/basemetals/recipes/lead_crossbow.json index a86d12c0..465f2b56 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/lead_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:lead_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_door.json b/src/main/resources/assets/basemetals/recipes/lead_door.json index 72137658..89e7bf9e 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_door.json +++ b/src/main/resources/assets/basemetals/recipes/lead_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:lead_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_fishingrod.json b/src/main/resources/assets/basemetals/recipes/lead_fishingrod.json index fe7a5b38..9d3151d8 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/lead_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:lead_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_gear.json b/src/main/resources/assets/basemetals/recipes/lead_gear.json index 4823b921..699461f2 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_gear.json +++ b/src/main/resources/assets/basemetals/recipes/lead_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:lead_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_helmet.json b/src/main/resources/assets/basemetals/recipes/lead_helmet.json index 28a6b6fd..8ee33192 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/lead_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:lead_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/lead_helmet_plate_repair.json index 2cc30281..f899aa47 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/lead_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Lead", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/lead_hoe.json b/src/main/resources/assets/basemetals/recipes/lead_hoe.json index 0022dcaf..90ac1a77 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/lead_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:lead_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_horsearmor.json b/src/main/resources/assets/basemetals/recipes/lead_horsearmor.json index 26748064..973a645a 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/lead_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:lead_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_ingot.json b/src/main/resources/assets/basemetals/recipes/lead_ingot.json index aa83d6a1..fb7a9c4b 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/lead_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:lead_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_leggings.json b/src/main/resources/assets/basemetals/recipes/lead_leggings.json index 7ffe30ad..9ed52845 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/lead_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:lead_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/lead_leggings_plate_repair.json index 6eaacb5d..697d86d3 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/lead_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Lead", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/lead_lever.json b/src/main/resources/assets/basemetals/recipes/lead_lever.json index 60c216e8..aad6685a 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_lever.json +++ b/src/main/resources/assets/basemetals/recipes/lead_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:lead_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_nugget.json b/src/main/resources/assets/basemetals/recipes/lead_nugget.json index e9d73163..b469eca7 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/lead_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:lead_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_pickaxe.json b/src/main/resources/assets/basemetals/recipes/lead_pickaxe.json index 98d7a9f4..c7ed7f44 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/lead_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:lead_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_plate.json b/src/main/resources/assets/basemetals/recipes/lead_plate.json index 474d20e9..d0b464ee 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_plate.json +++ b/src/main/resources/assets/basemetals/recipes/lead_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:lead_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_powder.json b/src/main/resources/assets/basemetals/recipes/lead_powder.json index 769cbfa2..92e67521 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_powder.json +++ b/src/main/resources/assets/basemetals/recipes/lead_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:lead_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_pressureplate.json b/src/main/resources/assets/basemetals/recipes/lead_pressureplate.json index 71b97c88..a7443fa6 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/lead_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:lead_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_rod.json b/src/main/resources/assets/basemetals/recipes/lead_rod.json index 0cb6e206..9f9422f7 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_rod.json +++ b/src/main/resources/assets/basemetals/recipes/lead_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:lead_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/lead_scythe.json b/src/main/resources/assets/basemetals/recipes/lead_scythe.json index b35f2f91..1f9f597e 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/lead_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:lead_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/lead_shears.json b/src/main/resources/assets/basemetals/recipes/lead_shears.json index 50f21d2e..22bd2187 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_shears.json +++ b/src/main/resources/assets/basemetals/recipes/lead_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:lead_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_shield.json b/src/main/resources/assets/basemetals/recipes/lead_shield.json index e780da33..d066c627 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_shield.json +++ b/src/main/resources/assets/basemetals/recipes/lead_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:lead_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/lead_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/lead_shield_plate_repair.json index 6e5c68ae..239da5eb 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/lead_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Lead", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/lead_shovel.json b/src/main/resources/assets/basemetals/recipes/lead_shovel.json index 1a8228d8..0b84df30 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/lead_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:lead_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_slab.json b/src/main/resources/assets/basemetals/recipes/lead_slab.json index 6343d73e..22362058 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_slab.json +++ b/src/main/resources/assets/basemetals/recipes/lead_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:lead_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_smallpowder.json b/src/main/resources/assets/basemetals/recipes/lead_smallpowder.json index 4a73c3c1..d0630420 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/lead_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:lead_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_stairs.json b/src/main/resources/assets/basemetals/recipes/lead_stairs.json index 3c4934df..f313ad0f 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/lead_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:lead_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_sword.json b/src/main/resources/assets/basemetals/recipes/lead_sword.json index 682517e7..e2a81dd4 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_sword.json +++ b/src/main/resources/assets/basemetals/recipes/lead_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:lead_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_trapdoor.json b/src/main/resources/assets/basemetals/recipes/lead_trapdoor.json index e86eab24..623e02a3 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/lead_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:lead_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/lead_wall.json b/src/main/resources/assets/basemetals/recipes/lead_wall.json index 925ebf60..27610734 100644 --- a/src/main/resources/assets/basemetals/recipes/lead_wall.json +++ b/src/main/resources/assets/basemetals/recipes/lead_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:lead_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/minecart.json b/src/main/resources/assets/basemetals/recipes/minecart.json index b78516eb..008bdffe 100644 --- a/src/main/resources/assets/basemetals/recipes/minecart.json +++ b/src/main/resources/assets/basemetals/recipes/minecart.json @@ -16,5 +16,5 @@ "result": { "item": "minecraft:minecart" }, - "group": "vanilla" + "group": "minecraft:minecart" } diff --git a/src/main/resources/assets/basemetals/recipes/mithril_arrow.json b/src/main/resources/assets/basemetals/recipes/mithril_arrow.json index 49963f3f..78977dd3 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:mithril_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_axe.json b/src/main/resources/assets/basemetals/recipes/mithril_axe.json index 66cd8236..f4293402 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_axe.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:mithril_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_bars_1.json b/src/main/resources/assets/basemetals/recipes/mithril_bars_1.json index cbcf86fc..27f35d88 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:mithril_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_bars_2.json b/src/main/resources/assets/basemetals/recipes/mithril_bars_2.json index 145a2a91..6503dc7a 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:mithril_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_blend_base.json b/src/main/resources/assets/basemetals/recipes/mithril_blend_base.json index 317dc17b..61fdcb31 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_blend_base.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_blend_base.json @@ -23,7 +23,7 @@ "ore": "ingotMercury" } ], - "group": "alloys", + "group": "basemetals:mithril_blend", "conditions": [ { "type": "forge:and", diff --git a/src/main/resources/assets/basemetals/recipes/mithril_blend_base_alternate.json b/src/main/resources/assets/basemetals/recipes/mithril_blend_base_alternate.json index 2a477b13..e8b137b5 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_blend_base_alternate.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_blend_base_alternate.json @@ -21,7 +21,7 @@ "ore": "ingotMercury" } ], - "group": "alloys", + "group": "basemetals:mithril_blend", "conditions": [ { "type": "forge:and", diff --git a/src/main/resources/assets/basemetals/recipes/mithril_blend_smallblend.json b/src/main/resources/assets/basemetals/recipes/mithril_blend_smallblend.json index 222033ec..7e9e0f57 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_blend_smallblend.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_blend_smallblend.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:mithril_blend" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_block.json b/src/main/resources/assets/basemetals/recipes/mithril_block.json index 0070d851..6bb0c202 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_block.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:mithril_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_block_ingot.json b/src/main/resources/assets/basemetals/recipes/mithril_block_ingot.json index 88b6b932..120ad128 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:mithril_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:mithril_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_bolt.json b/src/main/resources/assets/basemetals/recipes/mithril_bolt.json index 96ac93c2..30194a22 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:mithril_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_boots.json b/src/main/resources/assets/basemetals/recipes/mithril_boots.json index de8cb3b1..93d41ee7 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_boots.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:mithril_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_bow.json b/src/main/resources/assets/basemetals/recipes/mithril_bow.json index 6ca6c70d..b17bede4 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_bow.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:mithril_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_button.json b/src/main/resources/assets/basemetals/recipes/mithril_button.json index 5cad040b..3dc0d710 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_button.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:mithril_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_chestplate.json b/src/main/resources/assets/basemetals/recipes/mithril_chestplate.json index 6e517c1d..e77d453e 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:mithril_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_crackhammer.json b/src/main/resources/assets/basemetals/recipes/mithril_crackhammer.json index 5cf0d5aa..23712a9a 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:mithril_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_crossbow.json b/src/main/resources/assets/basemetals/recipes/mithril_crossbow.json index 5268061d..5a2c4379 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:mithril_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_door.json b/src/main/resources/assets/basemetals/recipes/mithril_door.json index a3b2b5e0..24dea8d4 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_door.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:mithril_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_fishingrod.json b/src/main/resources/assets/basemetals/recipes/mithril_fishingrod.json index dbc56643..463812c2 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:mithril_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_gear.json b/src/main/resources/assets/basemetals/recipes/mithril_gear.json index 4857d74b..32b84012 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_gear.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:mithril_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_helmet.json b/src/main/resources/assets/basemetals/recipes/mithril_helmet.json index 70b878e1..7eefef7f 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:mithril_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_hoe.json b/src/main/resources/assets/basemetals/recipes/mithril_hoe.json index 132d0a7d..03da77fe 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:mithril_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_horsearmor.json b/src/main/resources/assets/basemetals/recipes/mithril_horsearmor.json index 1ceb3d2e..30bee997 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:mithril_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_ingot.json b/src/main/resources/assets/basemetals/recipes/mithril_ingot.json index aa1b545b..e0f6efe6 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:mithril_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_leggings.json b/src/main/resources/assets/basemetals/recipes/mithril_leggings.json index fbc96932..b4d3e6e9 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:mithril_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_lever.json b/src/main/resources/assets/basemetals/recipes/mithril_lever.json index 75e64425..a75e6001 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_lever.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:mithril_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_nugget.json b/src/main/resources/assets/basemetals/recipes/mithril_nugget.json index 8b0032d5..44531dd3 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:mithril_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_pickaxe.json b/src/main/resources/assets/basemetals/recipes/mithril_pickaxe.json index f4d2e9ca..b0d69855 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:mithril_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_plate.json b/src/main/resources/assets/basemetals/recipes/mithril_plate.json index 41b38911..1e64c4d4 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_plate.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:mithril_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_powder.json b/src/main/resources/assets/basemetals/recipes/mithril_powder.json index 32a2600e..ce64ee0b 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_powder.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:mithril_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_pressureplate.json b/src/main/resources/assets/basemetals/recipes/mithril_pressureplate.json index 36d41e2c..80702113 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:mithril_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_rod.json b/src/main/resources/assets/basemetals/recipes/mithril_rod.json index 572036ac..a143729c 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_rod.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:mithril_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/mithril_scythe.json b/src/main/resources/assets/basemetals/recipes/mithril_scythe.json index 71e64729..b7e9964f 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:mithril_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/mithril_shears.json b/src/main/resources/assets/basemetals/recipes/mithril_shears.json index e69d004b..7830e8e2 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_shears.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:mithril_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_shield.json b/src/main/resources/assets/basemetals/recipes/mithril_shield.json index 3ebe7a87..492e941f 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_shield.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:mithril_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/mithril_shovel.json b/src/main/resources/assets/basemetals/recipes/mithril_shovel.json index 89f17e30..f0cf0b05 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:mithril_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_slab.json b/src/main/resources/assets/basemetals/recipes/mithril_slab.json index 9bfdbf1e..256e7210 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_slab.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:mithril_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_smallblend_blend.json b/src/main/resources/assets/basemetals/recipes/mithril_smallblend_blend.json index 222b0bdd..701ba155 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_smallblend_blend.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_smallblend_blend.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:mithril_smallblend" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_smallpowder.json b/src/main/resources/assets/basemetals/recipes/mithril_smallpowder.json index 08a4e4ff..9879920d 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:mithril_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_stairs.json b/src/main/resources/assets/basemetals/recipes/mithril_stairs.json index 1d09223a..9ec93ea1 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:mithril_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_sword.json b/src/main/resources/assets/basemetals/recipes/mithril_sword.json index 758795af..a8642ca6 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_sword.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:mithril_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_trapdoor.json b/src/main/resources/assets/basemetals/recipes/mithril_trapdoor.json index 5f747ba9..e7b92552 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:mithril_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/mithril_wall.json b/src/main/resources/assets/basemetals/recipes/mithril_wall.json index eb7ae562..899d9512 100644 --- a/src/main/resources/assets/basemetals/recipes/mithril_wall.json +++ b/src/main/resources/assets/basemetals/recipes/mithril_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:mithril_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_arrow.json b/src/main/resources/assets/basemetals/recipes/nickel_arrow.json index c0426240..29b60bf9 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:nickel_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_axe.json b/src/main/resources/assets/basemetals/recipes/nickel_axe.json index 6e7f1eea..5be80112 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_axe.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:nickel_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_bars_1.json b/src/main/resources/assets/basemetals/recipes/nickel_bars_1.json index 2d912f3b..8e7b3cc0 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:nickel_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_bars_2.json b/src/main/resources/assets/basemetals/recipes/nickel_bars_2.json index ad8cce97..1a9525f3 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:nickel_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_block.json b/src/main/resources/assets/basemetals/recipes/nickel_block.json index 731a92a8..c74d50fb 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_block.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:nickel_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_block_ingot.json b/src/main/resources/assets/basemetals/recipes/nickel_block_ingot.json index 3591f928..e95167b0 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:nickel_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:nickel_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_bolt.json b/src/main/resources/assets/basemetals/recipes/nickel_bolt.json index 197140de..2289b4cd 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:nickel_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_boots.json b/src/main/resources/assets/basemetals/recipes/nickel_boots.json index f6bb5b8f..bb39a2cf 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_boots.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:nickel_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/nickel_boots_plate_repair.json index bcbcc306..aa332a7c 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Nickel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/nickel_bow.json b/src/main/resources/assets/basemetals/recipes/nickel_bow.json index d8b060d7..7a263b5c 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_bow.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:nickel_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_button.json b/src/main/resources/assets/basemetals/recipes/nickel_button.json index dc1c7aea..2715f5dc 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_button.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:nickel_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_chestplate.json b/src/main/resources/assets/basemetals/recipes/nickel_chestplate.json index de1ff62f..2c1f295e 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:nickel_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/nickel_chestplate_plate_repair.json index 03638fff..00ad13bc 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Nickel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/nickel_crackhammer.json b/src/main/resources/assets/basemetals/recipes/nickel_crackhammer.json index 071f3089..1600654e 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:nickel_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_crossbow.json b/src/main/resources/assets/basemetals/recipes/nickel_crossbow.json index 1c9c1bb5..1efae1fd 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:nickel_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_door.json b/src/main/resources/assets/basemetals/recipes/nickel_door.json index c1202e3e..a0926a0c 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_door.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:nickel_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_fishingrod.json b/src/main/resources/assets/basemetals/recipes/nickel_fishingrod.json index b099ae3c..015cc593 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:nickel_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_gear.json b/src/main/resources/assets/basemetals/recipes/nickel_gear.json index 2a715c43..6be64558 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_gear.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:nickel_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_helmet.json b/src/main/resources/assets/basemetals/recipes/nickel_helmet.json index 44303f79..d239fb34 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:nickel_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/nickel_helmet_plate_repair.json index 2304f01c..ea49df73 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Nickel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/nickel_hoe.json b/src/main/resources/assets/basemetals/recipes/nickel_hoe.json index 973a15b0..5893954a 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:nickel_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_horsearmor.json b/src/main/resources/assets/basemetals/recipes/nickel_horsearmor.json index 77b10454..af932996 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:nickel_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_ingot.json b/src/main/resources/assets/basemetals/recipes/nickel_ingot.json index 58a310b8..03f06faa 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:nickel_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_leggings.json b/src/main/resources/assets/basemetals/recipes/nickel_leggings.json index 3be3b573..45a4a59a 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:nickel_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/nickel_leggings_plate_repair.json index 283e2e51..fd5bbb0a 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Nickel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/nickel_lever.json b/src/main/resources/assets/basemetals/recipes/nickel_lever.json index 3234b3b3..ef7ff3e0 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_lever.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:nickel_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_nugget.json b/src/main/resources/assets/basemetals/recipes/nickel_nugget.json index b0a18af1..05b75dbe 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:nickel_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_pickaxe.json b/src/main/resources/assets/basemetals/recipes/nickel_pickaxe.json index c6d4f733..0ae806b5 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:nickel_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_plate.json b/src/main/resources/assets/basemetals/recipes/nickel_plate.json index 50a14404..bd33e12a 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_plate.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:nickel_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_powder.json b/src/main/resources/assets/basemetals/recipes/nickel_powder.json index dfda6b21..2fd20f12 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_powder.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:nickel_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_pressureplate.json b/src/main/resources/assets/basemetals/recipes/nickel_pressureplate.json index 361dc36f..cf43940f 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:nickel_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_rod.json b/src/main/resources/assets/basemetals/recipes/nickel_rod.json index 62f224d1..4e3010d5 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_rod.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:nickel_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/nickel_scythe.json b/src/main/resources/assets/basemetals/recipes/nickel_scythe.json index 20d2ec3d..4cd3f5ff 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:nickel_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/nickel_shears.json b/src/main/resources/assets/basemetals/recipes/nickel_shears.json index 7419ffd5..5458510e 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_shears.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:nickel_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_shield.json b/src/main/resources/assets/basemetals/recipes/nickel_shield.json index a61bcec9..b6b9a58f 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_shield.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:nickel_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/nickel_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/nickel_shield_plate_repair.json index f222fc82..c59a8af2 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Nickel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/nickel_shovel.json b/src/main/resources/assets/basemetals/recipes/nickel_shovel.json index a1e81db2..bb021343 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:nickel_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_slab.json b/src/main/resources/assets/basemetals/recipes/nickel_slab.json index 702c2e6b..9c6cb98b 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_slab.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:nickel_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_smallpowder.json b/src/main/resources/assets/basemetals/recipes/nickel_smallpowder.json index cf3d58aa..6faef3ad 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:nickel_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_stairs.json b/src/main/resources/assets/basemetals/recipes/nickel_stairs.json index 68602d59..4aea505d 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:nickel_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_sword.json b/src/main/resources/assets/basemetals/recipes/nickel_sword.json index f26683f1..c83a2e38 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_sword.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:nickel_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_trapdoor.json b/src/main/resources/assets/basemetals/recipes/nickel_trapdoor.json index 229a441b..ad6d2223 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:nickel_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/nickel_wall.json b/src/main/resources/assets/basemetals/recipes/nickel_wall.json index 50b54392..a23af116 100644 --- a/src/main/resources/assets/basemetals/recipes/nickel_wall.json +++ b/src/main/resources/assets/basemetals/recipes/nickel_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:nickel_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_arrow.json b/src/main/resources/assets/basemetals/recipes/obsidian_arrow.json index 942083b5..886050e6 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_arrow" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_axe.json b/src/main/resources/assets/basemetals/recipes/obsidian_axe.json index a77ca4fa..2ccc5a3e 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_axe.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_axe" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_bars_1.json b/src/main/resources/assets/basemetals/recipes/obsidian_bars_1.json index 8ca911c2..3673ca77 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_bars" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_bars_2.json b/src/main/resources/assets/basemetals/recipes/obsidian_bars_2.json index 2a19637a..559568de 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_bars" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_block.json b/src/main/resources/assets/basemetals/recipes/obsidian_block.json index 27cea393..0f58b1cd 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_block.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_block.json @@ -31,5 +31,5 @@ ] } ], - "group": "vanilla" + "group": "minecraft:obsidian" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_bolt.json b/src/main/resources/assets/basemetals/recipes/obsidian_bolt.json index 9e069b90..58f9caa3 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_bolt.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_bolt" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_boots.json b/src/main/resources/assets/basemetals/recipes/obsidian_boots.json index 97ace049..ac67dd72 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_boots.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_boots" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_bow.json b/src/main/resources/assets/basemetals/recipes/obsidian_bow.json index 6ac921d4..0ede7964 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_bow.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_bow" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_button.json b/src/main/resources/assets/basemetals/recipes/obsidian_button.json index e2f9a04a..b9998da1 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_button.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_button" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_chestplate.json b/src/main/resources/assets/basemetals/recipes/obsidian_chestplate.json index 8f572b41..1822ccc8 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_chestplate" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_crackhammer.json b/src/main/resources/assets/basemetals/recipes/obsidian_crackhammer.json index d0569c36..5cb1eb9e 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_crackhammer" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_crossbow.json b/src/main/resources/assets/basemetals/recipes/obsidian_crossbow.json index 67f4a2d0..26417683 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_crossbow" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_door.json b/src/main/resources/assets/basemetals/recipes/obsidian_door.json index 89490b48..1bb1a949 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_door.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_door" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_fishingrod.json b/src/main/resources/assets/basemetals/recipes/obsidian_fishingrod.json index b6bca21f..82bebe3d 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_fishing_rod" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_gear.json b/src/main/resources/assets/basemetals/recipes/obsidian_gear.json index ff6128eb..d07adeaf 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_gear.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "vanilla" + "group": "basemetals:obsidian_gear" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_helmet.json b/src/main/resources/assets/basemetals/recipes/obsidian_helmet.json index a30abbbe..71bfc4a0 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_helmet" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_hoe.json b/src/main/resources/assets/basemetals/recipes/obsidian_hoe.json index e9449d67..63e06167 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_hoe" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_horsearmor.json b/src/main/resources/assets/basemetals/recipes/obsidian_horsearmor.json index deda8767..cd480561 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:obsidian_horse_armor" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_ingot.json b/src/main/resources/assets/basemetals/recipes/obsidian_ingot.json index f2ffdc93..64352915 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "minecraft:obsidian" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_leggings.json b/src/main/resources/assets/basemetals/recipes/obsidian_leggings.json index 198de955..5d11627c 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_leggings" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_lever.json b/src/main/resources/assets/basemetals/recipes/obsidian_lever.json index f33450d0..64a289e8 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_lever.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_lever" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_nugget.json b/src/main/resources/assets/basemetals/recipes/obsidian_nugget.json index 6791ab82..6193bd95 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_nugget" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_pickaxe.json b/src/main/resources/assets/basemetals/recipes/obsidian_pickaxe.json index cf9f2abf..efded911 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_pickaxe" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_powder.json b/src/main/resources/assets/basemetals/recipes/obsidian_powder.json index 1b1bc9a3..c07eaf93 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_powder.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_powder" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_pressureplate.json b/src/main/resources/assets/basemetals/recipes/obsidian_pressureplate.json index 28d8bc15..d8298680 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_pressure_plate" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_rod.json b/src/main/resources/assets/basemetals/recipes/obsidian_rod.json index 28abf116..c7bc5dbb 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_rod.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:obsidian_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_scythe.json b/src/main/resources/assets/basemetals/recipes/obsidian_scythe.json index db262eb6..711403fe 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:obsidian_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_shears.json b/src/main/resources/assets/basemetals/recipes/obsidian_shears.json index 67838125..4312ac20 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_shears.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_shears" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_shield.json b/src/main/resources/assets/basemetals/recipes/obsidian_shield.json index e1a9b17c..da24154e 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_shield.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_shovel.json b/src/main/resources/assets/basemetals/recipes/obsidian_shovel.json index fcc08ae2..d62d3f95 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_shovel" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_slab.json b/src/main/resources/assets/basemetals/recipes/obsidian_slab.json index 5232ae39..4c5aff3b 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_slab.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_slab" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_smallpowder.json b/src/main/resources/assets/basemetals/recipes/obsidian_smallpowder.json index b8963232..13e3255d 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_smallpowder" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_stairs.json b/src/main/resources/assets/basemetals/recipes/obsidian_stairs.json index 59186ee3..1050c961 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_stairs" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_sword.json b/src/main/resources/assets/basemetals/recipes/obsidian_sword.json index 12a5d48e..06a04bf9 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_sword.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_sword.json @@ -40,5 +40,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_sword" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_trapdoor.json b/src/main/resources/assets/basemetals/recipes/obsidian_trapdoor.json index 8f37d0d1..c9d5d696 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_trapdoor" } diff --git a/src/main/resources/assets/basemetals/recipes/obsidian_wall.json b/src/main/resources/assets/basemetals/recipes/obsidian_wall.json index a285c58e..03fbc1ea 100644 --- a/src/main/resources/assets/basemetals/recipes/obsidian_wall.json +++ b/src/main/resources/assets/basemetals/recipes/obsidian_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:obsidian_wall" } diff --git a/src/main/resources/assets/basemetals/recipes/pewter_arrow.json b/src/main/resources/assets/basemetals/recipes/pewter_arrow.json index c17e8154..6db22c7a 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:pewter_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_axe.json b/src/main/resources/assets/basemetals/recipes/pewter_axe.json index d15c7271..0b43d524 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_axe.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:pewter_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_bars_1.json b/src/main/resources/assets/basemetals/recipes/pewter_bars_1.json index 86f8e6e3..699716dc 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:pewter_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_bars_2.json b/src/main/resources/assets/basemetals/recipes/pewter_bars_2.json index 63761e86..da0598d2 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:pewter_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_blend_base.json b/src/main/resources/assets/basemetals/recipes/pewter_blend_base.json index 89f933ed..a55a5ee2 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_blend_base.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_blend_base.json @@ -19,7 +19,7 @@ "ore": "dustLead" } ], - "group": "alloys", + "group": "basemetals:pewter_blend", "conditions": [ { "type": "forge:and", @@ -52,4 +52,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_blend_smallblend.json b/src/main/resources/assets/basemetals/recipes/pewter_blend_smallblend.json index 225c90a4..7125d62d 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_blend_smallblend.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_blend_smallblend.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:pewter_blend" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_block.json b/src/main/resources/assets/basemetals/recipes/pewter_block.json index cd076e2b..52156042 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_block.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:pewter_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_block_ingot.json b/src/main/resources/assets/basemetals/recipes/pewter_block_ingot.json index 8e613d5e..7d410726 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:pewter_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:pewter_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_bolt.json b/src/main/resources/assets/basemetals/recipes/pewter_bolt.json index f16d835d..3657e66d 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:pewter_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_boots.json b/src/main/resources/assets/basemetals/recipes/pewter_boots.json index e247e9f8..ba09ab1b 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_boots.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:pewter_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/pewter_boots_plate_repair.json index dcba5b56..fbf07150 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Pewter", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/pewter_bow.json b/src/main/resources/assets/basemetals/recipes/pewter_bow.json index 65dc160a..8f1ebc8a 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_bow.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:pewter_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_button.json b/src/main/resources/assets/basemetals/recipes/pewter_button.json index 5f507c4b..7a81f3d1 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_button.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:pewter_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_chestplate.json b/src/main/resources/assets/basemetals/recipes/pewter_chestplate.json index 9aa519a8..3f82319a 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:pewter_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/pewter_chestplate_plate_repair.json index bda69bbc..acf1b855 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Pewter", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/pewter_crackhammer.json b/src/main/resources/assets/basemetals/recipes/pewter_crackhammer.json index 22a03b18..931291f0 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:pewter_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_crossbow.json b/src/main/resources/assets/basemetals/recipes/pewter_crossbow.json index ddf71d93..2072aa1e 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:pewter_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_door.json b/src/main/resources/assets/basemetals/recipes/pewter_door.json index 1aa463ee..e3f1a6c6 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_door.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:pewter_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_fishingrod.json b/src/main/resources/assets/basemetals/recipes/pewter_fishingrod.json index ef086498..6f6ee28a 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:pewter_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_gear.json b/src/main/resources/assets/basemetals/recipes/pewter_gear.json index aaf0c43d..a0c70677 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_gear.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:pewter_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_helmet.json b/src/main/resources/assets/basemetals/recipes/pewter_helmet.json index dd4e2404..2b5195bc 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:pewter_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/pewter_helmet_plate_repair.json index 097fef3f..988bcd9e 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Pewter", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/pewter_hoe.json b/src/main/resources/assets/basemetals/recipes/pewter_hoe.json index bc37898d..0abfae33 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:pewter_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_horsearmor.json b/src/main/resources/assets/basemetals/recipes/pewter_horsearmor.json index 8cee60ee..50d8937f 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:pewter_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_ingot.json b/src/main/resources/assets/basemetals/recipes/pewter_ingot.json index 9a49c4b6..1f2c0ac3 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:pewter_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_leggings.json b/src/main/resources/assets/basemetals/recipes/pewter_leggings.json index c76f5cab..4489b055 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:pewter_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/pewter_leggings_plate_repair.json index 9c7b63e9..36fab164 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Pewter", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/pewter_lever.json b/src/main/resources/assets/basemetals/recipes/pewter_lever.json index 4d932d7b..78ee36be 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_lever.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:pewter_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_nugget.json b/src/main/resources/assets/basemetals/recipes/pewter_nugget.json index 07b31a59..2fe6758c 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:pewter_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_pickaxe.json b/src/main/resources/assets/basemetals/recipes/pewter_pickaxe.json index c79752c4..2e55c3cd 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:pewter_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_plate.json b/src/main/resources/assets/basemetals/recipes/pewter_plate.json index 22336014..e2927189 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_plate.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:pewter_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_powder.json b/src/main/resources/assets/basemetals/recipes/pewter_powder.json index cca1d1f8..c6cf8b6c 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_powder.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:pewter_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_pressureplate.json b/src/main/resources/assets/basemetals/recipes/pewter_pressureplate.json index 49cd0a26..10a86b4a 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:pewter_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_rod.json b/src/main/resources/assets/basemetals/recipes/pewter_rod.json index 501203e7..2b032fa4 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_rod.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:pewter_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/pewter_scythe.json b/src/main/resources/assets/basemetals/recipes/pewter_scythe.json index bcd68901..9bec38dc 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:pewter_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/pewter_shears.json b/src/main/resources/assets/basemetals/recipes/pewter_shears.json index 87f76388..11bc7e57 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_shears.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:pewter_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_shield.json b/src/main/resources/assets/basemetals/recipes/pewter_shield.json index 970713a7..42c7a044 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_shield.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:pewter_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/pewter_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/pewter_shield_plate_repair.json index 69fdf250..cf15006b 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Pewter", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/pewter_shovel.json b/src/main/resources/assets/basemetals/recipes/pewter_shovel.json index 8b9c47ea..b9787618 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:pewter_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_slab.json b/src/main/resources/assets/basemetals/recipes/pewter_slab.json index 315087a2..b81f100c 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_slab.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:pewter_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_smallblend_blend.json b/src/main/resources/assets/basemetals/recipes/pewter_smallblend_blend.json index 37bfeb95..e056bd06 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_smallblend_blend.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_smallblend_blend.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:pewter_smallblend" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_smallpowder.json b/src/main/resources/assets/basemetals/recipes/pewter_smallpowder.json index 15bc962a..ad67d883 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:pewter_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_stairs.json b/src/main/resources/assets/basemetals/recipes/pewter_stairs.json index 5c74bbf2..8bff908f 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:pewter_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_sword.json b/src/main/resources/assets/basemetals/recipes/pewter_sword.json index 2c485bfe..5983260f 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_sword.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:pewter_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_trapdoor.json b/src/main/resources/assets/basemetals/recipes/pewter_trapdoor.json index df706a5a..c9dc1438 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:pewter_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/pewter_wall.json b/src/main/resources/assets/basemetals/recipes/pewter_wall.json index 4452d43f..2052988e 100644 --- a/src/main/resources/assets/basemetals/recipes/pewter_wall.json +++ b/src/main/resources/assets/basemetals/recipes/pewter_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:pewter_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/piston.json b/src/main/resources/assets/basemetals/recipes/piston.json index 7bc65588..2caf7b4c 100644 --- a/src/main/resources/assets/basemetals/recipes/piston.json +++ b/src/main/resources/assets/basemetals/recipes/piston.json @@ -29,5 +29,5 @@ "result": { "item": "minecraft:piston" }, - "group": "vanilla" + "group": "minecraft:piston" } diff --git a/src/main/resources/assets/basemetals/recipes/platinum_arrow.json b/src/main/resources/assets/basemetals/recipes/platinum_arrow.json index b4ba190e..91d37974 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:platinum_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_axe.json b/src/main/resources/assets/basemetals/recipes/platinum_axe.json index 77f823ce..25efda1e 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_axe.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:platinum_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_bars_1.json b/src/main/resources/assets/basemetals/recipes/platinum_bars_1.json index e6cedb51..e3ce19a1 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:platinum_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_bars_2.json b/src/main/resources/assets/basemetals/recipes/platinum_bars_2.json index 02d78a0c..1781252d 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:platinum_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_block.json b/src/main/resources/assets/basemetals/recipes/platinum_block.json index e2fdf61f..de337404 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_block.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:platinum_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_block_ingot.json b/src/main/resources/assets/basemetals/recipes/platinum_block_ingot.json index a80a99af..d1b25c71 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:platinum_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:platinum_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_bolt.json b/src/main/resources/assets/basemetals/recipes/platinum_bolt.json index 53f056a7..2a197675 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:platinum_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_boots.json b/src/main/resources/assets/basemetals/recipes/platinum_boots.json index 166da48f..b76689c5 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_boots.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:platinum_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/platinum_boots_plate_repair.json index 047bce90..7fcafd2c 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Platinum", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/platinum_bow.json b/src/main/resources/assets/basemetals/recipes/platinum_bow.json index 4e9a3eb2..476f05ec 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_bow.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:platinum_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_button.json b/src/main/resources/assets/basemetals/recipes/platinum_button.json index c04f2708..def99802 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_button.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:platinum_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_chestplate.json b/src/main/resources/assets/basemetals/recipes/platinum_chestplate.json index 3d37f225..7c1508aa 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:platinum_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/platinum_chestplate_plate_repair.json index 6a56833b..2464e741 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Platinum", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/platinum_crackhammer.json b/src/main/resources/assets/basemetals/recipes/platinum_crackhammer.json index 9a624769..0946c01d 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:platinum_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_crossbow.json b/src/main/resources/assets/basemetals/recipes/platinum_crossbow.json index 10c0e134..7c344bd4 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:platinum_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_door.json b/src/main/resources/assets/basemetals/recipes/platinum_door.json index 4ed32a3f..9cc99425 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_door.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:platinum_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_fishingrod.json b/src/main/resources/assets/basemetals/recipes/platinum_fishingrod.json index 672a3108..cf70190b 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:platinum_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_gear.json b/src/main/resources/assets/basemetals/recipes/platinum_gear.json index b4d10225..358b98f1 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_gear.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:platinum_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_helmet.json b/src/main/resources/assets/basemetals/recipes/platinum_helmet.json index 2fa869bd..66c0974a 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:platinum_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/platinum_helmet_plate_repair.json index 6ea4a9d4..0b6bcb56 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Platinum", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/platinum_hoe.json b/src/main/resources/assets/basemetals/recipes/platinum_hoe.json index 4a47558d..c0aa2cc6 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:platinum_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_horsearmor.json b/src/main/resources/assets/basemetals/recipes/platinum_horsearmor.json index 7993f0a9..f7c4a291 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:platinum_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_ingot.json b/src/main/resources/assets/basemetals/recipes/platinum_ingot.json index da514efd..17ace4a3 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:platinum_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_leggings.json b/src/main/resources/assets/basemetals/recipes/platinum_leggings.json index 972dcf48..5bc14166 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:platinum_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/platinum_leggings_plate_repair.json index c69c47bc..4f439041 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Platinum", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/platinum_lever.json b/src/main/resources/assets/basemetals/recipes/platinum_lever.json index 5780ef02..4501480a 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_lever.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:platinum_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_nugget.json b/src/main/resources/assets/basemetals/recipes/platinum_nugget.json index 7bfe8aec..bdb199ee 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:platinum_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_pickaxe.json b/src/main/resources/assets/basemetals/recipes/platinum_pickaxe.json index cff57af2..d7f41d16 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:platinum_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_plate.json b/src/main/resources/assets/basemetals/recipes/platinum_plate.json index 2caba15b..4edb5c7f 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_plate.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:platinum_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_powder.json b/src/main/resources/assets/basemetals/recipes/platinum_powder.json index a80633de..8500e8fd 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_powder.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:platinum_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_pressureplate.json b/src/main/resources/assets/basemetals/recipes/platinum_pressureplate.json index a3ad44e5..16093874 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:platinum_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_rod.json b/src/main/resources/assets/basemetals/recipes/platinum_rod.json index 4b7eb3bc..9e032e4c 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_rod.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:platinum_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/platinum_scythe.json b/src/main/resources/assets/basemetals/recipes/platinum_scythe.json index f7c85591..41bb2f67 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:platinum_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/platinum_shears.json b/src/main/resources/assets/basemetals/recipes/platinum_shears.json index 0f53111c..1f152c39 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_shears.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:platinum_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_shield.json b/src/main/resources/assets/basemetals/recipes/platinum_shield.json index 18226d93..583f6d78 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_shield.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:platinum_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/platinum_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/platinum_shield_plate_repair.json index 4c0ebdaf..4e3768ec 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Platinum", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/platinum_shovel.json b/src/main/resources/assets/basemetals/recipes/platinum_shovel.json index d312c59a..427b477a 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:platinum_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_slab.json b/src/main/resources/assets/basemetals/recipes/platinum_slab.json index cd136fa1..c7c331e9 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_slab.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:platinum_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_smallpowder.json b/src/main/resources/assets/basemetals/recipes/platinum_smallpowder.json index c70adf09..ed90db30 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:platinum_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_stairs.json b/src/main/resources/assets/basemetals/recipes/platinum_stairs.json index 23470a63..1b422822 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:platinum_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_sword.json b/src/main/resources/assets/basemetals/recipes/platinum_sword.json index 98865d68..cac27869 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_sword.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:platinum_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_trapdoor.json b/src/main/resources/assets/basemetals/recipes/platinum_trapdoor.json index ad43a032..e86ccb5f 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:platinum_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/platinum_wall.json b/src/main/resources/assets/basemetals/recipes/platinum_wall.json index 15e552ae..c054eb22 100644 --- a/src/main/resources/assets/basemetals/recipes/platinum_wall.json +++ b/src/main/resources/assets/basemetals/recipes/platinum_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:platinum_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/quartz_arrow.json b/src/main/resources/assets/basemetals/recipes/quartz_arrow.json index 0552e97d..dcef7af6 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_arrow" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_axe.json b/src/main/resources/assets/basemetals/recipes/quartz_axe.json index 0893daaa..8f94b72e 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_axe.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_axe" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_bars_1.json b/src/main/resources/assets/basemetals/recipes/quartz_bars_1.json index 2a32f711..59c2d9d9 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_bars" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_bars_2.json b/src/main/resources/assets/basemetals/recipes/quartz_bars_2.json index 48a4114b..731bb3bf 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_bars" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_bolt.json b/src/main/resources/assets/basemetals/recipes/quartz_bolt.json index f84f5197..c7afb8a5 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_bolt.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_bolt" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_boots.json b/src/main/resources/assets/basemetals/recipes/quartz_boots.json index 5e2e8882..b6278d70 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_boots.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_boots" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_bow.json b/src/main/resources/assets/basemetals/recipes/quartz_bow.json index e705845f..d8332e8f 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_bow.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_bow" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_button.json b/src/main/resources/assets/basemetals/recipes/quartz_button.json index 007b36b1..fa89c6ec 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_button.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_button" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_chestplate.json b/src/main/resources/assets/basemetals/recipes/quartz_chestplate.json index f2509a7f..5d106115 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_chestplate" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_crackhammer.json b/src/main/resources/assets/basemetals/recipes/quartz_crackhammer.json index e0e88996..c8db6bc6 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_crackhammer" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_crossbow.json b/src/main/resources/assets/basemetals/recipes/quartz_crossbow.json index 2eddc0f9..a1d2b34e 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_crossbow" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_door.json b/src/main/resources/assets/basemetals/recipes/quartz_door.json index 98877a53..04e2eb66 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_door.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_door" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_fishingrod.json b/src/main/resources/assets/basemetals/recipes/quartz_fishingrod.json index 4a8ce60a..22078b48 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_fishing_rod" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_gear.json b/src/main/resources/assets/basemetals/recipes/quartz_gear.json index 42a8c627..2d5c3c3b 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_gear.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "vanilla" + "group": "basemetals:quartz_gear" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_helmet.json b/src/main/resources/assets/basemetals/recipes/quartz_helmet.json index 67920907..1a4ee044 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_helmet" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_hoe.json b/src/main/resources/assets/basemetals/recipes/quartz_hoe.json index b930648d..2f6576e2 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_hoe" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_horsearmor.json b/src/main/resources/assets/basemetals/recipes/quartz_horsearmor.json index aebca8e4..ad4d43ef 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:quartz_horse_armor" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_ingot.json b/src/main/resources/assets/basemetals/recipes/quartz_ingot.json index 3b7ecee5..fac5a0d8 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "minecraft:quartz" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_leggings.json b/src/main/resources/assets/basemetals/recipes/quartz_leggings.json index 3e7a5762..ad8dea73 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_leggings" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_lever.json b/src/main/resources/assets/basemetals/recipes/quartz_lever.json index 18b5452f..10182fb9 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_lever.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_lever" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_nugget.json b/src/main/resources/assets/basemetals/recipes/quartz_nugget.json index cfd80311..5bd29c46 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_nugget" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_pickaxe.json b/src/main/resources/assets/basemetals/recipes/quartz_pickaxe.json index cb3804a3..324e3e4f 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_pickaxe" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_powder.json b/src/main/resources/assets/basemetals/recipes/quartz_powder.json index 57137a67..b84a5ca6 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_powder.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_powder" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_pressureplate.json b/src/main/resources/assets/basemetals/recipes/quartz_pressureplate.json index 7f6fb6a9..18cc11c4 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_pressure_plate" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_rod.json b/src/main/resources/assets/basemetals/recipes/quartz_rod.json index 0a8e0e84..27cbd5f0 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_rod.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:quartz_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/quartz_scythe.json b/src/main/resources/assets/basemetals/recipes/quartz_scythe.json index b720b09f..09c5ec15 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:quartz_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_shears.json b/src/main/resources/assets/basemetals/recipes/quartz_shears.json index 0e80b7ff..c36b22a2 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_shears.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_shears" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_shield.json b/src/main/resources/assets/basemetals/recipes/quartz_shield.json index 15353707..abfd136f 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_shield.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_shovel.json b/src/main/resources/assets/basemetals/recipes/quartz_shovel.json index e4dd44d7..49c9f57b 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_shovel" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_smallpowder.json b/src/main/resources/assets/basemetals/recipes/quartz_smallpowder.json index 01072b17..14f9ed47 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_smallpowder" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_sword.json b/src/main/resources/assets/basemetals/recipes/quartz_sword.json index ab9ef48f..d215c9c6 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_sword.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_sword.json @@ -40,5 +40,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_sword" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_trapdoor.json b/src/main/resources/assets/basemetals/recipes/quartz_trapdoor.json index 648544ba..f524bf09 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_trapdoor.json @@ -35,5 +35,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_trapdoor" } diff --git a/src/main/resources/assets/basemetals/recipes/quartz_wall.json b/src/main/resources/assets/basemetals/recipes/quartz_wall.json index 436f906a..ed23dd71 100644 --- a/src/main/resources/assets/basemetals/recipes/quartz_wall.json +++ b/src/main/resources/assets/basemetals/recipes/quartz_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:quartz_wall" } diff --git a/src/main/resources/assets/basemetals/recipes/rail.json b/src/main/resources/assets/basemetals/recipes/rail.json index 88753312..690e4d74 100644 --- a/src/main/resources/assets/basemetals/recipes/rail.json +++ b/src/main/resources/assets/basemetals/recipes/rail.json @@ -22,5 +22,5 @@ "item": "minecraft:rail", "count": 16 }, - "group": "vanilla" + "group": "minecraft:rail" } diff --git a/src/main/resources/assets/basemetals/recipes/redstone_powder.json b/src/main/resources/assets/basemetals/recipes/redstone_powder.json index 5918b39e..cee80035 100644 --- a/src/main/resources/assets/basemetals/recipes/redstone_powder.json +++ b/src/main/resources/assets/basemetals/recipes/redstone_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "vanilla" + "group": "minecraft:redstone" } diff --git a/src/main/resources/assets/basemetals/recipes/redstone_smallpowder.json b/src/main/resources/assets/basemetals/recipes/redstone_smallpowder.json index a28cee91..57297a93 100644 --- a/src/main/resources/assets/basemetals/recipes/redstone_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/redstone_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:redstone_smallpowder" } diff --git a/src/main/resources/assets/basemetals/recipes/silver_arrow.json b/src/main/resources/assets/basemetals/recipes/silver_arrow.json index c1da0133..9b4300ec 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/silver_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:silver_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_axe.json b/src/main/resources/assets/basemetals/recipes/silver_axe.json index eb712635..0334aae3 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_axe.json +++ b/src/main/resources/assets/basemetals/recipes/silver_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:silver_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_bars_1.json b/src/main/resources/assets/basemetals/recipes/silver_bars_1.json index 45270399..cd631bf4 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/silver_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:silver_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_bars_2.json b/src/main/resources/assets/basemetals/recipes/silver_bars_2.json index e6d329c1..8493415f 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/silver_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:silver_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_block.json b/src/main/resources/assets/basemetals/recipes/silver_block.json index c9382484..a5ed062a 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_block.json +++ b/src/main/resources/assets/basemetals/recipes/silver_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:silver_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_block_ingot.json b/src/main/resources/assets/basemetals/recipes/silver_block_ingot.json index 35d6b623..a2d13a4a 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/silver_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:silver_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:silver_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_bolt.json b/src/main/resources/assets/basemetals/recipes/silver_bolt.json index 13b41f93..3b5177a2 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/silver_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:silver_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_boots.json b/src/main/resources/assets/basemetals/recipes/silver_boots.json index 06264e60..9d1dafc6 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_boots.json +++ b/src/main/resources/assets/basemetals/recipes/silver_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:silver_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/silver_boots_plate_repair.json index c77ed6d1..2d740939 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/silver_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Silver", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/silver_bow.json b/src/main/resources/assets/basemetals/recipes/silver_bow.json index 5a1fd241..ccdaa10f 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_bow.json +++ b/src/main/resources/assets/basemetals/recipes/silver_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:silver_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_button.json b/src/main/resources/assets/basemetals/recipes/silver_button.json index 8366d9c1..67a453b0 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_button.json +++ b/src/main/resources/assets/basemetals/recipes/silver_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:silver_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_chestplate.json b/src/main/resources/assets/basemetals/recipes/silver_chestplate.json index 00de617d..c94c8565 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/silver_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:silver_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/silver_chestplate_plate_repair.json index e7285fd5..2c8a1710 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/silver_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Silver", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/silver_crackhammer.json b/src/main/resources/assets/basemetals/recipes/silver_crackhammer.json index 23614d20..9b79add9 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/silver_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:silver_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_crossbow.json b/src/main/resources/assets/basemetals/recipes/silver_crossbow.json index c0cf0b01..1f181e2c 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/silver_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:silver_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_door.json b/src/main/resources/assets/basemetals/recipes/silver_door.json index 664da140..31da1732 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_door.json +++ b/src/main/resources/assets/basemetals/recipes/silver_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:silver_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_fishingrod.json b/src/main/resources/assets/basemetals/recipes/silver_fishingrod.json index aa8f0b31..a38bf453 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/silver_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:silver_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_gear.json b/src/main/resources/assets/basemetals/recipes/silver_gear.json index 7909590a..0e80f24d 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_gear.json +++ b/src/main/resources/assets/basemetals/recipes/silver_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:silver_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_helmet.json b/src/main/resources/assets/basemetals/recipes/silver_helmet.json index 1404edc3..6f32f34c 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/silver_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:silver_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/silver_helmet_plate_repair.json index 1f2da6e8..4d8f8006 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/silver_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Silver", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/silver_hoe.json b/src/main/resources/assets/basemetals/recipes/silver_hoe.json index 494d894f..0e8026a3 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/silver_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:silver_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_horsearmor.json b/src/main/resources/assets/basemetals/recipes/silver_horsearmor.json index c8c692cc..e9bfb89e 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/silver_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:silver_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_ingot.json b/src/main/resources/assets/basemetals/recipes/silver_ingot.json index be628a8b..97c6bdec 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/silver_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:silver_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_leggings.json b/src/main/resources/assets/basemetals/recipes/silver_leggings.json index ba754bd8..62445dcd 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/silver_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:silver_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/silver_leggings_plate_repair.json index bcd9162e..7c58f6a5 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/silver_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Silver", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/silver_lever.json b/src/main/resources/assets/basemetals/recipes/silver_lever.json index fbd412ab..bf56ab48 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_lever.json +++ b/src/main/resources/assets/basemetals/recipes/silver_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:silver_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_nugget.json b/src/main/resources/assets/basemetals/recipes/silver_nugget.json index 59683c50..065c128a 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/silver_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:silver_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_pickaxe.json b/src/main/resources/assets/basemetals/recipes/silver_pickaxe.json index ac9ebfa4..75b9a057 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/silver_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:silver_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_plate.json b/src/main/resources/assets/basemetals/recipes/silver_plate.json index 39bb93d0..ca528f98 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_plate.json +++ b/src/main/resources/assets/basemetals/recipes/silver_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:silver_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_powder.json b/src/main/resources/assets/basemetals/recipes/silver_powder.json index 921a8e52..b7a85c73 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_powder.json +++ b/src/main/resources/assets/basemetals/recipes/silver_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:silver_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_pressureplate.json b/src/main/resources/assets/basemetals/recipes/silver_pressureplate.json index 22585f33..7dea5198 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/silver_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:silver_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_rod.json b/src/main/resources/assets/basemetals/recipes/silver_rod.json index e6e6eca7..1b5b5b62 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_rod.json +++ b/src/main/resources/assets/basemetals/recipes/silver_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:silver_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/silver_scythe.json b/src/main/resources/assets/basemetals/recipes/silver_scythe.json index 166ef70e..c0b8e5cb 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/silver_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:silver_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/silver_shears.json b/src/main/resources/assets/basemetals/recipes/silver_shears.json index 082fc1af..c49e2b76 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_shears.json +++ b/src/main/resources/assets/basemetals/recipes/silver_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:silver_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_shield.json b/src/main/resources/assets/basemetals/recipes/silver_shield.json index f92d31c4..b4b54dc0 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_shield.json +++ b/src/main/resources/assets/basemetals/recipes/silver_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:silver_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/silver_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/silver_shield_plate_repair.json index 00480806..4e2e692d 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/silver_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Silver", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/silver_shovel.json b/src/main/resources/assets/basemetals/recipes/silver_shovel.json index 18502d2b..0e69ffde 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/silver_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:silver_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_slab.json b/src/main/resources/assets/basemetals/recipes/silver_slab.json index 0e4c6521..f830c557 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_slab.json +++ b/src/main/resources/assets/basemetals/recipes/silver_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:silver_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_smallpowder.json b/src/main/resources/assets/basemetals/recipes/silver_smallpowder.json index 8e5d8b9d..e0cebebe 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/silver_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:silver_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_stairs.json b/src/main/resources/assets/basemetals/recipes/silver_stairs.json index 082e0307..8a5d0e9b 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/silver_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:silver_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_sword.json b/src/main/resources/assets/basemetals/recipes/silver_sword.json index 09e959a1..5bc6c534 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_sword.json +++ b/src/main/resources/assets/basemetals/recipes/silver_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:silver_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_trapdoor.json b/src/main/resources/assets/basemetals/recipes/silver_trapdoor.json index 51197dfb..a99ddede 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/silver_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:silver_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/silver_wall.json b/src/main/resources/assets/basemetals/recipes/silver_wall.json index 02c729a1..97365849 100644 --- a/src/main/resources/assets/basemetals/recipes/silver_wall.json +++ b/src/main/resources/assets/basemetals/recipes/silver_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:silver_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_arrow.json b/src/main/resources/assets/basemetals/recipes/starsteel_arrow.json index 41c60bbc..fbc8e649 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:starsteel_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_axe.json b/src/main/resources/assets/basemetals/recipes/starsteel_axe.json index 86b653dc..5ab13013 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_axe.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:starsteel_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_bars_1.json b/src/main/resources/assets/basemetals/recipes/starsteel_bars_1.json index 7bd60af3..afac5bd7 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:starsteel_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_bars_2.json b/src/main/resources/assets/basemetals/recipes/starsteel_bars_2.json index 4b83dde2..965db5c7 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:starsteel_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_block.json b/src/main/resources/assets/basemetals/recipes/starsteel_block.json index b49d81f4..a4f03034 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_block.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:starsteel_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_block_ingot.json b/src/main/resources/assets/basemetals/recipes/starsteel_block_ingot.json index 82499032..790ec771 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:starsteel_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:starsteel_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_bolt.json b/src/main/resources/assets/basemetals/recipes/starsteel_bolt.json index 7e12df27..40d6ec03 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:starsteel_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_boots.json b/src/main/resources/assets/basemetals/recipes/starsteel_boots.json index aec14863..97c79c4b 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_boots.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:starsteel_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/starsteel_boots_plate_repair.json index b2021ded..adad4d85 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "StarSteel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_bow.json b/src/main/resources/assets/basemetals/recipes/starsteel_bow.json index 3cad872d..ade1e3ca 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_bow.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:starsteel_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_button.json b/src/main/resources/assets/basemetals/recipes/starsteel_button.json index 9951fc2e..98b0cd0f 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_button.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:starsteel_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_chestplate.json b/src/main/resources/assets/basemetals/recipes/starsteel_chestplate.json index 4007724f..56dce99c 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:starsteel_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/starsteel_chestplate_plate_repair.json index a4b0469a..3aad9282 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "StarSteel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_crackhammer.json b/src/main/resources/assets/basemetals/recipes/starsteel_crackhammer.json index a06ecebb..f9523221 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:starsteel_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_crossbow.json b/src/main/resources/assets/basemetals/recipes/starsteel_crossbow.json index c5f479b1..60b47a72 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:starsteel_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_door.json b/src/main/resources/assets/basemetals/recipes/starsteel_door.json index ba3c21a8..233f5cfa 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_door.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:starsteel_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_fishingrod.json b/src/main/resources/assets/basemetals/recipes/starsteel_fishingrod.json index 0acc5def..808d8198 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:starsteel_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_gear.json b/src/main/resources/assets/basemetals/recipes/starsteel_gear.json index 1a7a2d60..e2e66058 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_gear.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:starsteel_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_helmet.json b/src/main/resources/assets/basemetals/recipes/starsteel_helmet.json index 4cd09150..4c8ca589 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:starsteel_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/starsteel_helmet_plate_repair.json index 0d20d8f4..1d442aad 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "StarSteel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_hoe.json b/src/main/resources/assets/basemetals/recipes/starsteel_hoe.json index 6ffbe611..786f60dd 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:starsteel_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_horsearmor.json b/src/main/resources/assets/basemetals/recipes/starsteel_horsearmor.json index a15395f4..46ef0b49 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:starsteel_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_ingot.json b/src/main/resources/assets/basemetals/recipes/starsteel_ingot.json index 382ee616..e5305e52 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:starsteel_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_leggings.json b/src/main/resources/assets/basemetals/recipes/starsteel_leggings.json index ac244a68..d7435624 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:starsteel_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/starsteel_leggings_plate_repair.json index 9c9755a6..9d9e2b37 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "StarSteel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_lever.json b/src/main/resources/assets/basemetals/recipes/starsteel_lever.json index f6e13d6e..2dd339b7 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_lever.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:starsteel_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_nugget.json b/src/main/resources/assets/basemetals/recipes/starsteel_nugget.json index 0f1e788d..5d3bbd04 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:starsteel_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_pickaxe.json b/src/main/resources/assets/basemetals/recipes/starsteel_pickaxe.json index 9acfafde..6af4fa80 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:starsteel_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_plate.json b/src/main/resources/assets/basemetals/recipes/starsteel_plate.json index f12e37c9..91a5566c 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_plate.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:starsteel_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_powder.json b/src/main/resources/assets/basemetals/recipes/starsteel_powder.json index 5991726b..215c77e3 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_powder.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:starsteel_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_pressureplate.json b/src/main/resources/assets/basemetals/recipes/starsteel_pressureplate.json index 0f159be7..f666a6ab 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:starsteel_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_rod.json b/src/main/resources/assets/basemetals/recipes/starsteel_rod.json index 7025f834..e4d2276f 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_rod.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:starsteel_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_scythe.json b/src/main/resources/assets/basemetals/recipes/starsteel_scythe.json index cd32d246..22be4af1 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:starsteel_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_shears.json b/src/main/resources/assets/basemetals/recipes/starsteel_shears.json index 4dddf410..873c41d1 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_shears.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:starsteel_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_shield.json b/src/main/resources/assets/basemetals/recipes/starsteel_shield.json index 723418b9..4b4a0e96 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_shield.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:starsteel_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/starsteel_shield_plate_repair.json index 51791543..9eb526e7 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "StarSteel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_shovel.json b/src/main/resources/assets/basemetals/recipes/starsteel_shovel.json index 1760cbd1..6ebb1dcb 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:starsteel_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_slab.json b/src/main/resources/assets/basemetals/recipes/starsteel_slab.json index 8f4255cc..99d46b9c 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_slab.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:starsteel_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_smallpowder.json b/src/main/resources/assets/basemetals/recipes/starsteel_smallpowder.json index 205c40c6..7f01fde9 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:starsteel_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_stairs.json b/src/main/resources/assets/basemetals/recipes/starsteel_stairs.json index 6d371bef..3dcae4e3 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:starsteel_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_sword.json b/src/main/resources/assets/basemetals/recipes/starsteel_sword.json index 5a4b9269..1dec12a4 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_sword.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:starsteel_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_trapdoor.json b/src/main/resources/assets/basemetals/recipes/starsteel_trapdoor.json index 81115579..453b04fb 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:starsteel_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/starsteel_wall.json b/src/main/resources/assets/basemetals/recipes/starsteel_wall.json index f83401e8..207bf28f 100644 --- a/src/main/resources/assets/basemetals/recipes/starsteel_wall.json +++ b/src/main/resources/assets/basemetals/recipes/starsteel_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:starsteel_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_anvil.json b/src/main/resources/assets/basemetals/recipes/steel_anvil.json index ad6142b4..ec684b10 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_anvil.json +++ b/src/main/resources/assets/basemetals/recipes/steel_anvil.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" + "group": "basemetals:steel_anvil" } diff --git a/src/main/resources/assets/basemetals/recipes/steel_arrow.json b/src/main/resources/assets/basemetals/recipes/steel_arrow.json index 96c34742..fe30c200 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/steel_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:steel_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_axe.json b/src/main/resources/assets/basemetals/recipes/steel_axe.json index 06e1ca3b..38d07f99 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_axe.json +++ b/src/main/resources/assets/basemetals/recipes/steel_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:steel_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_bars_1.json b/src/main/resources/assets/basemetals/recipes/steel_bars_1.json index ba86f29f..5d5eb503 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/steel_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:steel_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_bars_2.json b/src/main/resources/assets/basemetals/recipes/steel_bars_2.json index 4d73c72b..39ef7f62 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/steel_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:steel_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_blend_base.json b/src/main/resources/assets/basemetals/recipes/steel_blend_base.json index 38ca5a52..76620ebc 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_blend_base.json +++ b/src/main/resources/assets/basemetals/recipes/steel_blend_base.json @@ -43,7 +43,7 @@ "ore": "dustCoal" } ], - "group": "alloys", + "group": "basemetals:steel_blend", "conditions": [ { "type": "forge:and", @@ -71,4 +71,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_blend_smallblend.json b/src/main/resources/assets/basemetals/recipes/steel_blend_smallblend.json index 16458ec4..5fef9bc4 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_blend_smallblend.json +++ b/src/main/resources/assets/basemetals/recipes/steel_blend_smallblend.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:steel_blend" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_block.json b/src/main/resources/assets/basemetals/recipes/steel_block.json index c2085851..8d5019c8 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_block.json +++ b/src/main/resources/assets/basemetals/recipes/steel_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:steel_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_block_ingot.json b/src/main/resources/assets/basemetals/recipes/steel_block_ingot.json index 560c92ea..0fd096e6 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/steel_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:steel_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:steel_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_bolt.json b/src/main/resources/assets/basemetals/recipes/steel_bolt.json index 29cbeaa6..04ad5eef 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/steel_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:steel_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_boots.json b/src/main/resources/assets/basemetals/recipes/steel_boots.json index d6742bce..25094561 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_boots.json +++ b/src/main/resources/assets/basemetals/recipes/steel_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:steel_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/steel_boots_plate_repair.json index a8673175..ffad8653 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/steel_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Steel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/steel_bow.json b/src/main/resources/assets/basemetals/recipes/steel_bow.json index 8f96b6e8..e3e2840c 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_bow.json +++ b/src/main/resources/assets/basemetals/recipes/steel_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:steel_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_button.json b/src/main/resources/assets/basemetals/recipes/steel_button.json index a4055109..611ce5fa 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_button.json +++ b/src/main/resources/assets/basemetals/recipes/steel_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:steel_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_chestplate.json b/src/main/resources/assets/basemetals/recipes/steel_chestplate.json index 4616fdbc..b0012a0b 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/steel_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:steel_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/steel_chestplate_plate_repair.json index 19e770d8..51202573 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/steel_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Steel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/steel_crackhammer.json b/src/main/resources/assets/basemetals/recipes/steel_crackhammer.json index b0773112..9cfe8e0b 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/steel_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:steel_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_crossbow.json b/src/main/resources/assets/basemetals/recipes/steel_crossbow.json index ae26f90f..29ea44cc 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/steel_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:steel_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_door.json b/src/main/resources/assets/basemetals/recipes/steel_door.json index 2f148f74..9a0653a7 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_door.json +++ b/src/main/resources/assets/basemetals/recipes/steel_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:steel_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_fishingrod.json b/src/main/resources/assets/basemetals/recipes/steel_fishingrod.json index dccca022..a0639dc5 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/steel_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:steel_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_gear.json b/src/main/resources/assets/basemetals/recipes/steel_gear.json index caf083a7..0884455f 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_gear.json +++ b/src/main/resources/assets/basemetals/recipes/steel_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:steel_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_helmet.json b/src/main/resources/assets/basemetals/recipes/steel_helmet.json index 232e11d0..b52d3257 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/steel_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:steel_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/steel_helmet_plate_repair.json index 59f8d891..34dc8904 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/steel_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Steel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/steel_hoe.json b/src/main/resources/assets/basemetals/recipes/steel_hoe.json index 4dcddd50..2ece6e59 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/steel_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:steel_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_horsearmor.json b/src/main/resources/assets/basemetals/recipes/steel_horsearmor.json index 917273b9..1d4f6474 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/steel_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:steel_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_ingot.json b/src/main/resources/assets/basemetals/recipes/steel_ingot.json index 0b30c3da..91b39232 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/steel_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:steel_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_leggings.json b/src/main/resources/assets/basemetals/recipes/steel_leggings.json index f1cf19d8..165f0115 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/steel_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:steel_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/steel_leggings_plate_repair.json index 27ae5804..1fa437ae 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/steel_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Steel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/steel_lever.json b/src/main/resources/assets/basemetals/recipes/steel_lever.json index 8a50f08b..7426b7a9 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_lever.json +++ b/src/main/resources/assets/basemetals/recipes/steel_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:steel_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_nugget.json b/src/main/resources/assets/basemetals/recipes/steel_nugget.json index f3fc112f..ec56fe77 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/steel_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:steel_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_pickaxe.json b/src/main/resources/assets/basemetals/recipes/steel_pickaxe.json index 310f62ed..d2b613f3 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/steel_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:steel_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_plate.json b/src/main/resources/assets/basemetals/recipes/steel_plate.json index 4d433c5e..57e5493c 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_plate.json +++ b/src/main/resources/assets/basemetals/recipes/steel_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:steel_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_powder.json b/src/main/resources/assets/basemetals/recipes/steel_powder.json index c3ce3ecf..dd64ef42 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_powder.json +++ b/src/main/resources/assets/basemetals/recipes/steel_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:steel_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_pressureplate.json b/src/main/resources/assets/basemetals/recipes/steel_pressureplate.json index f69bf2e5..c85e4894 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/steel_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:steel_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_rod.json b/src/main/resources/assets/basemetals/recipes/steel_rod.json index b658dd52..80f2577e 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_rod.json +++ b/src/main/resources/assets/basemetals/recipes/steel_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:steel_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/steel_scythe.json b/src/main/resources/assets/basemetals/recipes/steel_scythe.json index 34d9cce5..87f4c8d0 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/steel_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:steel_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/steel_shears.json b/src/main/resources/assets/basemetals/recipes/steel_shears.json index 176f1d1a..17954f29 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_shears.json +++ b/src/main/resources/assets/basemetals/recipes/steel_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:steel_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_shield.json b/src/main/resources/assets/basemetals/recipes/steel_shield.json index 80868c39..4de44310 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_shield.json +++ b/src/main/resources/assets/basemetals/recipes/steel_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:steel_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/steel_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/steel_shield_plate_repair.json index eab75f97..7c3d1e74 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/steel_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Steel", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/steel_shovel.json b/src/main/resources/assets/basemetals/recipes/steel_shovel.json index 115ba9e0..3cb88255 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/steel_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:steel_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_slab.json b/src/main/resources/assets/basemetals/recipes/steel_slab.json index 0bf754e1..e8fc8b2b 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_slab.json +++ b/src/main/resources/assets/basemetals/recipes/steel_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:steel_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_smallblend_blend.json b/src/main/resources/assets/basemetals/recipes/steel_smallblend_blend.json index 9586d238..e32eca1a 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_smallblend_blend.json +++ b/src/main/resources/assets/basemetals/recipes/steel_smallblend_blend.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:steel_smallblend" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_smallpowder.json b/src/main/resources/assets/basemetals/recipes/steel_smallpowder.json index daca850d..0a9757da 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/steel_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:steel_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_stairs.json b/src/main/resources/assets/basemetals/recipes/steel_stairs.json index 11d638c0..9b0f5393 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/steel_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:steel_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_sword.json b/src/main/resources/assets/basemetals/recipes/steel_sword.json index f40a3ce5..e16c8852 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_sword.json +++ b/src/main/resources/assets/basemetals/recipes/steel_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:steel_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_trapdoor.json b/src/main/resources/assets/basemetals/recipes/steel_trapdoor.json index 0cdf5bc1..c4e48e00 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/steel_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:steel_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/steel_wall.json b/src/main/resources/assets/basemetals/recipes/steel_wall.json index c758a1eb..6f5318a4 100644 --- a/src/main/resources/assets/basemetals/recipes/steel_wall.json +++ b/src/main/resources/assets/basemetals/recipes/steel_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:steel_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/stone_anvil.json b/src/main/resources/assets/basemetals/recipes/stone_anvil.json index 2046f2b4..f08b3b7c 100644 --- a/src/main/resources/assets/basemetals/recipes/stone_anvil.json +++ b/src/main/resources/assets/basemetals/recipes/stone_anvil.json @@ -47,5 +47,5 @@ ] } ], - "group": "tools" + "group": "basemetals:stone_anvil" } diff --git a/src/main/resources/assets/basemetals/recipes/stone_crackhammer.json b/src/main/resources/assets/basemetals/recipes/stone_crackhammer.json index 133dafe0..77be1b7d 100644 --- a/src/main/resources/assets/basemetals/recipes/stone_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/stone_crackhammer.json @@ -33,5 +33,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:stone_crackhammer" } diff --git a/src/main/resources/assets/basemetals/recipes/stone_scythe.json b/src/main/resources/assets/basemetals/recipes/stone_scythe.json index 305b48bd..a105b9bf 100644 --- a/src/main/resources/assets/basemetals/recipes/stone_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/stone_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:stone_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/tin_arrow.json b/src/main/resources/assets/basemetals/recipes/tin_arrow.json index e8f02e5e..d05488c8 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/tin_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:tin_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_axe.json b/src/main/resources/assets/basemetals/recipes/tin_axe.json index 0231a95f..96c203ca 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_axe.json +++ b/src/main/resources/assets/basemetals/recipes/tin_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:tin_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_bars_1.json b/src/main/resources/assets/basemetals/recipes/tin_bars_1.json index 8d4af8b3..064a7d13 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/tin_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:tin_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_bars_2.json b/src/main/resources/assets/basemetals/recipes/tin_bars_2.json index 7bec0132..01173086 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/tin_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:tin_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_block.json b/src/main/resources/assets/basemetals/recipes/tin_block.json index 3c00df48..b96e0ad4 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_block.json +++ b/src/main/resources/assets/basemetals/recipes/tin_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:tin_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_block_ingot.json b/src/main/resources/assets/basemetals/recipes/tin_block_ingot.json index 1fb5b0f7..b50904e1 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/tin_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:tin_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:tin_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_bolt.json b/src/main/resources/assets/basemetals/recipes/tin_bolt.json index 29ed3105..db07551e 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/tin_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:tin_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_boots.json b/src/main/resources/assets/basemetals/recipes/tin_boots.json index 174db7bb..2531f137 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_boots.json +++ b/src/main/resources/assets/basemetals/recipes/tin_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:tin_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/tin_boots_plate_repair.json index d2fb6eac..73e3087b 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/tin_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Tin", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/tin_bow.json b/src/main/resources/assets/basemetals/recipes/tin_bow.json index 0471c1bf..551059c4 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_bow.json +++ b/src/main/resources/assets/basemetals/recipes/tin_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:tin_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_button.json b/src/main/resources/assets/basemetals/recipes/tin_button.json index 752e551b..1c220d82 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_button.json +++ b/src/main/resources/assets/basemetals/recipes/tin_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:tin_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_chestplate.json b/src/main/resources/assets/basemetals/recipes/tin_chestplate.json index 9053568e..7dd71f36 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/tin_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:tin_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/tin_chestplate_plate_repair.json index 72d0f5bf..8ac7b4d6 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/tin_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Tin", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/tin_crackhammer.json b/src/main/resources/assets/basemetals/recipes/tin_crackhammer.json index 94004bde..1634e6c5 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/tin_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:tin_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_crossbow.json b/src/main/resources/assets/basemetals/recipes/tin_crossbow.json index 4cfd4950..89f32ef0 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/tin_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:tin_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_door.json b/src/main/resources/assets/basemetals/recipes/tin_door.json index 7c1c3121..3035bbb7 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_door.json +++ b/src/main/resources/assets/basemetals/recipes/tin_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:tin_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_fishingrod.json b/src/main/resources/assets/basemetals/recipes/tin_fishingrod.json index 2f715a71..b72aa924 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/tin_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:tin_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_gear.json b/src/main/resources/assets/basemetals/recipes/tin_gear.json index 6ae9217b..042b370d 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_gear.json +++ b/src/main/resources/assets/basemetals/recipes/tin_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:tin_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_helmet.json b/src/main/resources/assets/basemetals/recipes/tin_helmet.json index e757f220..97647f17 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/tin_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:tin_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/tin_helmet_plate_repair.json index 73e30bfd..c2470414 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/tin_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Tin", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/tin_hoe.json b/src/main/resources/assets/basemetals/recipes/tin_hoe.json index bd645b9f..ab617ca4 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/tin_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:tin_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_horsearmor.json b/src/main/resources/assets/basemetals/recipes/tin_horsearmor.json index 6230ad14..8e47702b 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/tin_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:tin_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_ingot.json b/src/main/resources/assets/basemetals/recipes/tin_ingot.json index f43df25e..3b79014e 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/tin_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:tin_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_leggings.json b/src/main/resources/assets/basemetals/recipes/tin_leggings.json index d2ecf157..d1ca8629 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/tin_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:tin_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/tin_leggings_plate_repair.json index 50126ac6..77f622b4 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/tin_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Tin", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/tin_lever.json b/src/main/resources/assets/basemetals/recipes/tin_lever.json index 0a17599d..46a86b47 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_lever.json +++ b/src/main/resources/assets/basemetals/recipes/tin_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:tin_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_nugget.json b/src/main/resources/assets/basemetals/recipes/tin_nugget.json index 6758be15..375ac9df 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/tin_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:tin_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_pickaxe.json b/src/main/resources/assets/basemetals/recipes/tin_pickaxe.json index 67875b64..c3499328 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/tin_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:tin_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_plate.json b/src/main/resources/assets/basemetals/recipes/tin_plate.json index d5df9a1d..4569caf6 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_plate.json +++ b/src/main/resources/assets/basemetals/recipes/tin_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:tin_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_powder.json b/src/main/resources/assets/basemetals/recipes/tin_powder.json index 54812e1b..d6f8dce6 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_powder.json +++ b/src/main/resources/assets/basemetals/recipes/tin_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:tin_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_pressureplate.json b/src/main/resources/assets/basemetals/recipes/tin_pressureplate.json index a6dfd956..e56ce3ba 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/tin_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:tin_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_rod.json b/src/main/resources/assets/basemetals/recipes/tin_rod.json index 2b6299fe..ad504d61 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_rod.json +++ b/src/main/resources/assets/basemetals/recipes/tin_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:tin_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/tin_scythe.json b/src/main/resources/assets/basemetals/recipes/tin_scythe.json index dae9303a..496930f2 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/tin_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:tin_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/tin_shears.json b/src/main/resources/assets/basemetals/recipes/tin_shears.json index 17facfc4..cf6ed741 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_shears.json +++ b/src/main/resources/assets/basemetals/recipes/tin_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:tin_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_shield.json b/src/main/resources/assets/basemetals/recipes/tin_shield.json index 2be32a7d..7b86199c 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_shield.json +++ b/src/main/resources/assets/basemetals/recipes/tin_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:tin_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/tin_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/tin_shield_plate_repair.json index 2192ea7c..15c3dfb4 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/tin_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Tin", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/tin_shovel.json b/src/main/resources/assets/basemetals/recipes/tin_shovel.json index 7b600461..679d2e65 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/tin_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:tin_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_slab.json b/src/main/resources/assets/basemetals/recipes/tin_slab.json index 75739384..3b04c822 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_slab.json +++ b/src/main/resources/assets/basemetals/recipes/tin_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:tin_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_smallpowder.json b/src/main/resources/assets/basemetals/recipes/tin_smallpowder.json index c3ec546c..77ebcf65 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/tin_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:tin_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_stairs.json b/src/main/resources/assets/basemetals/recipes/tin_stairs.json index c9141d3f..e0d600fc 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/tin_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:tin_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_sword.json b/src/main/resources/assets/basemetals/recipes/tin_sword.json index ce242035..5d3a33e4 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_sword.json +++ b/src/main/resources/assets/basemetals/recipes/tin_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:tin_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_trapdoor.json b/src/main/resources/assets/basemetals/recipes/tin_trapdoor.json index 191d4cb1..6e865364 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/tin_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:tin_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/tin_wall.json b/src/main/resources/assets/basemetals/recipes/tin_wall.json index b5258f5a..9954183f 100644 --- a/src/main/resources/assets/basemetals/recipes/tin_wall.json +++ b/src/main/resources/assets/basemetals/recipes/tin_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:tin_wall" +} diff --git a/src/main/resources/assets/basemetals/recipes/tripwire_hook.json b/src/main/resources/assets/basemetals/recipes/tripwire_hook.json index 60ab5ac8..a362dca9 100644 --- a/src/main/resources/assets/basemetals/recipes/tripwire_hook.json +++ b/src/main/resources/assets/basemetals/recipes/tripwire_hook.json @@ -25,5 +25,5 @@ "result": { "item": "minecraft:tripwire_hook" }, - "group": "vanilla" + "group": "minecraft:tripwire_hook" } diff --git a/src/main/resources/assets/basemetals/recipes/wood_crackhammer.json b/src/main/resources/assets/basemetals/recipes/wood_crackhammer.json index 30ad6bf3..55084f35 100644 --- a/src/main/resources/assets/basemetals/recipes/wood_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/wood_crackhammer.json @@ -33,5 +33,5 @@ ] } ], - "group": "vanilla" + "group": "basemetals:wood_crackhammer" } diff --git a/src/main/resources/assets/basemetals/recipes/wood_scythe.json b/src/main/resources/assets/basemetals/recipes/wood_scythe.json index 5ffb1dc4..1d5752fb 100644 --- a/src/main/resources/assets/basemetals/recipes/wood_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/wood_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:wood_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/zinc_arrow.json b/src/main/resources/assets/basemetals/recipes/zinc_arrow.json index 6d29a2ad..d382048f 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_arrow.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_arrow.json @@ -46,5 +46,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:zinc_arrow" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_axe.json b/src/main/resources/assets/basemetals/recipes/zinc_axe.json index f7f8498b..17404f61 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_axe.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_axe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:zinc_axe" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_bars_1.json b/src/main/resources/assets/basemetals/recipes/zinc_bars_1.json index dd5068fc..03b49245 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_bars_1.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_bars_1.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:zinc_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_bars_2.json b/src/main/resources/assets/basemetals/recipes/zinc_bars_2.json index 5c6b9c54..28b1690d 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_bars_2.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_bars_2.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:zinc_bars" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_block.json b/src/main/resources/assets/basemetals/recipes/zinc_block.json index 6ebc442a..967eab96 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_block.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_block.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:zinc_block" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_block_ingot.json b/src/main/resources/assets/basemetals/recipes/zinc_block_ingot.json index 487d9913..65d41b9a 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_block_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_block_ingot.json @@ -10,7 +10,7 @@ "item": "basemetals:zinc_ingot", "count": 9 }, - "group": "basics", + "group": "basemetals:zinc_ingot", "conditions": [ { "type": "forge:and", @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_bolt.json b/src/main/resources/assets/basemetals/recipes/zinc_bolt.json index 67e37a7e..223e1f03 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_bolt.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_bolt.json @@ -42,5 +42,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:zinc_bolt" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_boots.json b/src/main/resources/assets/basemetals/recipes/zinc_boots.json index 65873185..4cfcf6dd 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_boots.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_boots.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:zinc_boots" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_boots_plate_repair.json b/src/main/resources/assets/basemetals/recipes/zinc_boots_plate_repair.json index 3d3a9dea..62385cf0 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_boots_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_boots_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "boots", "material": "Zinc", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/zinc_bow.json b/src/main/resources/assets/basemetals/recipes/zinc_bow.json index 718ef659..4aa664e6 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_bow.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_bow.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:zinc_bow" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_button.json b/src/main/resources/assets/basemetals/recipes/zinc_button.json index c92215c0..eb9f6477 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_button.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_button.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:zinc_button" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_chestplate.json b/src/main/resources/assets/basemetals/recipes/zinc_chestplate.json index c52c27b7..41e82dde 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_chestplate.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_chestplate.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:zinc_chestplate" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_chestplate_plate_repair.json b/src/main/resources/assets/basemetals/recipes/zinc_chestplate_plate_repair.json index 46b9db41..d643fa2d 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_chestplate_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_chestplate_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "chestplate", "material": "Zinc", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/zinc_crackhammer.json b/src/main/resources/assets/basemetals/recipes/zinc_crackhammer.json index ad1768fc..1ad1dbb9 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_crackhammer.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_crackhammer.json @@ -39,5 +39,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:zinc_crackhammer" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_crossbow.json b/src/main/resources/assets/basemetals/recipes/zinc_crossbow.json index a9d0c155..94aa2a2d 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_crossbow.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_crossbow.json @@ -50,5 +50,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:zinc_crossbow" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_door.json b/src/main/resources/assets/basemetals/recipes/zinc_door.json index 485c998a..177b3749 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_door.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_door.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:zinc_door" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_fishingrod.json b/src/main/resources/assets/basemetals/recipes/zinc_fishingrod.json index 8aa49196..6e342163 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_fishingrod.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_fishingrod.json @@ -41,5 +41,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:zinc_fishing_rod" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_gear.json b/src/main/resources/assets/basemetals/recipes/zinc_gear.json index f7cfd338..8933bdf2 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_gear.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_gear.json @@ -42,5 +42,5 @@ } ], "config_key": "gear", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:zinc_gear" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_helmet.json b/src/main/resources/assets/basemetals/recipes/zinc_helmet.json index f4b5a2a8..8c8986a0 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_helmet.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_helmet.json @@ -36,5 +36,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:zinc_helmet" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_helmet_plate_repair.json b/src/main/resources/assets/basemetals/recipes/zinc_helmet_plate_repair.json index 199d0d8e..bd96a055 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_helmet_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_helmet_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "helmet", "material": "Zinc", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/zinc_hoe.json b/src/main/resources/assets/basemetals/recipes/zinc_hoe.json index 29602797..087e38d4 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_hoe.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_hoe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:zinc_hoe" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_horsearmor.json b/src/main/resources/assets/basemetals/recipes/zinc_horsearmor.json index 2336d481..ee5d29ba 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_horsearmor.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_horsearmor.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:zinc_horse_armor" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_ingot.json b/src/main/resources/assets/basemetals/recipes/zinc_ingot.json index d14c8a2c..9502c011 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_ingot.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_ingot.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:zinc_ingot" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_leggings.json b/src/main/resources/assets/basemetals/recipes/zinc_leggings.json index 2520a639..fb078337 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_leggings.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_leggings.json @@ -37,5 +37,5 @@ ] } ], - "group": "armor" -} \ No newline at end of file + "group": "basemetals:zinc_leggings" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_leggings_plate_repair.json b/src/main/resources/assets/basemetals/recipes/zinc_leggings_plate_repair.json index b48208a0..0f2fde09 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_leggings_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_leggings_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "leggings", "material": "Zinc", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/zinc_lever.json b/src/main/resources/assets/basemetals/recipes/zinc_lever.json index bce2a900..08562584 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_lever.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_lever.json @@ -45,5 +45,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:zinc_lever" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_nugget.json b/src/main/resources/assets/basemetals/recipes/zinc_nugget.json index c38df943..e93c1304 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_nugget.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_nugget.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:zinc_nugget" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_pickaxe.json b/src/main/resources/assets/basemetals/recipes/zinc_pickaxe.json index e4cfe345..61992386 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_pickaxe.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_pickaxe.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:zinc_pickaxe" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_plate.json b/src/main/resources/assets/basemetals/recipes/zinc_plate.json index 241c73de..0f4649de 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_plate.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_plate.json @@ -36,5 +36,5 @@ } ], "config_key": "plate", - "group": "misc" -} \ No newline at end of file + "group": "basemetals:zinc_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_powder.json b/src/main/resources/assets/basemetals/recipes/zinc_powder.json index a1b6a427..a3b5009c 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_powder.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_powder.json @@ -32,5 +32,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:zinc_powder" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_pressureplate.json b/src/main/resources/assets/basemetals/recipes/zinc_pressureplate.json index 47946b76..174ef448 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_pressureplate.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_pressureplate.json @@ -35,5 +35,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:zinc_pressure_plate" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_rod.json b/src/main/resources/assets/basemetals/recipes/zinc_rod.json index 69b54744..d9a06c5f 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_rod.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_rod.json @@ -37,6 +37,5 @@ "x", "x" ], - "group" : "misc" + "group": "basemetals:zinc_rod" } - diff --git a/src/main/resources/assets/basemetals/recipes/zinc_scythe.json b/src/main/resources/assets/basemetals/recipes/zinc_scythe.json index 6f408946..91c6e675 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_scythe.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_scythe.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" + "group": "basemetals:zinc_scythe" } diff --git a/src/main/resources/assets/basemetals/recipes/zinc_shears.json b/src/main/resources/assets/basemetals/recipes/zinc_shears.json index f2e525c9..eb8206a2 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_shears.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_shears.json @@ -36,5 +36,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:zinc_shears" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_shield.json b/src/main/resources/assets/basemetals/recipes/zinc_shield.json index 0801b1e2..9421248e 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_shield.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_shield.json @@ -41,5 +41,5 @@ ] } ], - "group": "armor" + "group": "basemetals:zinc_shield" } diff --git a/src/main/resources/assets/basemetals/recipes/zinc_shield_plate_repair.json b/src/main/resources/assets/basemetals/recipes/zinc_shield_plate_repair.json index 68a21a1a..a743d0c5 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_shield_plate_repair.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_shield_plate_repair.json @@ -1,5 +1,5 @@ { - "type": "mmdlib:armor_repair", + "type": "basemetals:armor_repair", "armorType": "shield", "material": "Zinc", "conditions": [ diff --git a/src/main/resources/assets/basemetals/recipes/zinc_shovel.json b/src/main/resources/assets/basemetals/recipes/zinc_shovel.json index e1d573d6..a5de690d 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_shovel.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_shovel.json @@ -41,5 +41,5 @@ ] } ], - "group": "tools" -} \ No newline at end of file + "group": "basemetals:zinc_shovel" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_slab.json b/src/main/resources/assets/basemetals/recipes/zinc_slab.json index b8df15ee..afbc2f7f 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_slab.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_slab.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:zinc_slab" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_smallpowder.json b/src/main/resources/assets/basemetals/recipes/zinc_smallpowder.json index 7afe2377..b85aedbc 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_smallpowder.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_smallpowder.json @@ -28,5 +28,5 @@ ] } ], - "group": "basics" -} \ No newline at end of file + "group": "basemetals:zinc_smallpowder" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_stairs.json b/src/main/resources/assets/basemetals/recipes/zinc_stairs.json index 80b8cd5b..0bbe90ad 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_stairs.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_stairs.json @@ -38,5 +38,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:zinc_stairs" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_sword.json b/src/main/resources/assets/basemetals/recipes/zinc_sword.json index 10fde6e8..06409cee 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_sword.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_sword.json @@ -41,5 +41,5 @@ ] } ], - "group": "weapon" -} \ No newline at end of file + "group": "basemetals:zinc_sword" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_trapdoor.json b/src/main/resources/assets/basemetals/recipes/zinc_trapdoor.json index 82a9d02a..64fa6450 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_trapdoor.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_trapdoor.json @@ -36,5 +36,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:zinc_trapdoor" +} diff --git a/src/main/resources/assets/basemetals/recipes/zinc_wall.json b/src/main/resources/assets/basemetals/recipes/zinc_wall.json index 3f9261ee..cfc1bead 100644 --- a/src/main/resources/assets/basemetals/recipes/zinc_wall.json +++ b/src/main/resources/assets/basemetals/recipes/zinc_wall.json @@ -37,5 +37,5 @@ ] } ], - "group": "misc" -} \ No newline at end of file + "group": "basemetals:zinc_wall" +} diff --git a/src/test/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreenTest.java b/src/test/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreenTest.java index 86593289..673b1422 100644 --- a/src/test/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreenTest.java +++ b/src/test/java/com/mcmoddev/basemetals/client/config/BaseMetalsConfigScreenTest.java @@ -23,7 +23,9 @@ class BaseMetalsConfigScreenTest { void rootContainsOnlyTheFiveHistoricalCategoriesInStableOrder() { final Configuration configuration = create(); final List elements = BaseMetalsConfigScreen.categoryElements(configuration); + assertEquals(BMeConfig.GUI_CATEGORIES.size(), elements.size()); + for (int index = 0; index < elements.size(); index++) { assertEquals(BMeConfig.GUI_CATEGORIES.get(index).toLowerCase(java.util.Locale.ROOT), elements.get(index).getName()); @@ -38,6 +40,7 @@ void rootContainsOnlyTheFiveHistoricalCategoriesInStableOrder() { void warningReportsOnlyNewlyDisabledGeneratedMaterials() { final Configuration configuration = create(); final Map before = BaseMetalsConfigScreen.snapshot(configuration); + configuration.getCategory(BMeConfig.MATERIALS_CAT).get("EnableColdiron").set(false); configuration.getCategory(BMeConfig.MATERIALS_CAT).get("EnableTin").set(false); configuration.getCategory(BMeConfig.MATERIALS_CAT).get("EnableAntimony").set(false); @@ -56,14 +59,16 @@ void warningReportsOnlyNewlyDisabledGeneratedMaterials() { void disposableConfigurationPersistsDoneValuesWhileRestoreModelsEscape() { final Configuration configuration = create(); final Map before = BaseMetalsConfigScreen.snapshot(configuration); + configuration.getCategory(BMeConfig.VANILLA_CAT).get("EnableGold").set(false); configuration.getCategory(BMeConfig.GENERAL_CAT) - .get(BMeConfig.CONTENT_MODE_PROPERTY).set("realism"); + .get(BMeConfig.CONTENT_MODE_PROPERTY).set("low_fantasy"); configuration.save(); final Configuration reloaded = create(); + assertFalse(reloaded.getCategory(BMeConfig.VANILLA_CAT).get("EnableGold").getBoolean()); - assertEquals("realism", reloaded.getCategory(BMeConfig.GENERAL_CAT) + assertEquals("low_fantasy", reloaded.getCategory(BMeConfig.GENERAL_CAT) .get(BMeConfig.CONTENT_MODE_PROPERTY).getString()); BaseMetalsConfigScreen.restore(before, configuration); diff --git a/src/test/java/com/mcmoddev/basemetals/client/config/ClientExtensionRegistrationContractTest.java b/src/test/java/com/mcmoddev/basemetals/client/config/ClientExtensionRegistrationContractTest.java index 58f526a3..c6ef75f0 100644 --- a/src/test/java/com/mcmoddev/basemetals/client/config/ClientExtensionRegistrationContractTest.java +++ b/src/test/java/com/mcmoddev/basemetals/client/config/ClientExtensionRegistrationContractTest.java @@ -17,6 +17,7 @@ void registersExactlyOneConventionalBaseMetalsExtensionFromTheClientProxy() thro final Path clientProxy = Paths.get("src", "main", "java", "com", "mcmoddev", "basemetals", "proxy", "ClientProxy.java"); final String source = new String(Files.readAllBytes(clientProxy), StandardCharsets.UTF_8); + assertEquals(1, occurrences(source, "WorldSettingsExtensionRegistry.registerConfigScreen")); assertTrue(source.contains("BaseMetals.MODID")); @@ -24,16 +25,18 @@ void registersExactlyOneConventionalBaseMetalsExtensionFromTheClientProxy() thro final Path commonProxy = clientProxy.resolveSibling("CommonProxy.java"); final String commonSource = new String(Files.readAllBytes(commonProxy), StandardCharsets.UTF_8); + assertFalse(commonSource.contains("WorldSettingsExtensionRegistry")); assertFalse(commonSource.contains("BaseMetalsConfigScreen")); } private static int occurrences(final String source, final String value) { int count = 0; - for (int index = 0; (index = source.indexOf(value, index)) >= 0; - index += value.length()) { + + for (int index = 0; (index = source.indexOf(value, index)) >= 0; index += value.length()) { count++; } + return count; } } diff --git a/src/test/java/com/mcmoddev/basemetals/client/config/ConfigLocalizationContractTest.java b/src/test/java/com/mcmoddev/basemetals/client/config/ConfigLocalizationContractTest.java index 949aa86b..8340c15c 100644 --- a/src/test/java/com/mcmoddev/basemetals/client/config/ConfigLocalizationContractTest.java +++ b/src/test/java/com/mcmoddev/basemetals/client/config/ConfigLocalizationContractTest.java @@ -32,19 +32,25 @@ void allEighteenLocalesDefineTheCompleteConfigurationVocabulary() throws Excepti final Path langDirectory = Paths.get("src", "main", "resources", "assets", "basemetals", "lang"); final List locales; + try (java.util.stream.Stream files = Files.list(langDirectory)) { locales = files.filter(path -> path.getFileName().toString().endsWith(".lang")) .sorted().collect(java.util.stream.Collectors.toList()); } + assertEquals(18, locales.size()); + final Map english = configurationValues( langDirectory.resolve("en_us.lang")); - assertEquals(64, english.size()); + + assertEquals(61, english.size()); for (final Path locale : locales) { final String text = new String(Files.readAllBytes(locale), StandardCharsets.UTF_8); final Map values = configurationValues(locale); + assertEquals(english.keySet(), values.keySet(), locale.toString()); + for (final String key : Arrays.asList( "config.basemetals.title=", "config.basemetals.restart_guidance=", "config.basemetals.category.general=", @@ -59,27 +65,29 @@ void allEighteenLocalesDefineTheCompleteConfigurationVocabulary() throws Excepti "config.basemetals.content_mode.high_fantasy.description=", "config.basemetals.content_mode.low_fantasy=", "config.basemetals.content_mode.low_fantasy.description=", - "config.basemetals.content_mode.realism=", - "config.basemetals.content_mode.realism.description=", "config.basemetals.warning.content_mode.title=", "config.basemetals.warning.content_mode.message=", - "config.basemetals.warning.content_mode.realism=", "config.basemetals.warning.confirm=", "config.basemetals.warning.disable_ores.title=", "config.basemetals.warning.disable_ores.message=", "config.basemetals.warning.disable_ores.confirm=")) { assertEquals(1, occurrences(text, key), locale + " " + key); } + for (final String material : MATERIALS) { final String key = "config.basemetals.material." + material + "="; + assertEquals(1, occurrences(text, key), locale + " " + key); } + assertTrue(text.contains("config.basemetals.category.metals.tooltip="), locale.toString()); + if (!STANDARD_ENGLISH_LOCALES.contains(locale.getFileName().toString())) { final long translated = english.entrySet().stream() .filter(entry -> !entry.getValue().equals(values.get(entry.getKey()))) .count(); + assertTrue(translated >= 20, locale + " still contains an English fallback configuration block"); } @@ -89,23 +97,28 @@ void allEighteenLocalesDefineTheCompleteConfigurationVocabulary() throws Excepti private static Map configurationValues(final Path locale) throws Exception { final Map values = new LinkedHashMap<>(); + for (final String line : Files.readAllLines(locale, StandardCharsets.UTF_8)) { if (!line.startsWith("config.basemetals.")) { continue; } + final int separator = line.indexOf('='); + assertTrue(separator > 0, locale + " malformed configuration translation: " + line); values.put(line.substring(0, separator), line.substring(separator + 1)); } + return values; } private static int occurrences(final String text, final String value) { int count = 0; - for (int index = 0; (index = text.indexOf(value, index)) >= 0; - index += value.length()) { + + for (int index = 0; (index = text.indexOf(value, index)) >= 0; index += value.length()) { count++; } + return count; } } diff --git a/src/test/java/com/mcmoddev/basemetals/client/renderer/BoltRendererContractTest.java b/src/test/java/com/mcmoddev/basemetals/client/renderer/BoltRendererContractTest.java index 25473cde..f7d1b90a 100644 --- a/src/test/java/com/mcmoddev/basemetals/client/renderer/BoltRendererContractTest.java +++ b/src/test/java/com/mcmoddev/basemetals/client/renderer/BoltRendererContractTest.java @@ -24,8 +24,8 @@ /** Locks the texture used by Base Metals' in-world bolt renderer. */ final class BoltRendererContractTest { - private static final ResourceLocation VANILLA_PROJECTILE_TEXTURE = - new ResourceLocation("minecraft", "textures/entity/projectiles/arrow.png"); + private static final ResourceLocation VANILLA_PROJECTILE_TEXTURE = new ResourceLocation("minecraft", + "textures/entity/projectiles/arrow.png"); @Test void boltRendererUsesAnExistingVanillaProjectileTexture() { @@ -43,24 +43,30 @@ void everyBoltItemModelRetainsItsMaterialTexture() throws IOException { final Path textureDirectory = Paths.get( "src/main/resources/assets/basemetals/textures/items"); final List models; + try (Stream files = Files.list(modelDirectory)) { models = files.filter(path -> path.getFileName().toString().endsWith("_bolt.json")) .sorted().collect(Collectors.toList()); } assertEquals(27, models.size(), "Unexpected Base Metals bolt model count"); + for (final Path modelPath : models) { final String fileName = modelPath.getFileName().toString(); final String itemName = fileName.substring(0, fileName.length() - ".json".length()); final JsonObject model = new JsonParser().parse(new String( Files.readAllBytes(modelPath), StandardCharsets.UTF_8)).getAsJsonObject(); + assertEquals("item/generated", model.get("parent").getAsString(), fileName); assertEquals("basemetals:items/" + itemName, model.getAsJsonObject("textures").get("layer0").getAsString(), fileName); final Path texturePath = textureDirectory.resolve(itemName + ".png"); + assertTrue(Files.isRegularFile(texturePath), "Missing texture for " + fileName); + final BufferedImage texture = javax.imageio.ImageIO.read(texturePath.toFile()); + assertNotNull(texture, "Unreadable texture for " + fileName); assertEquals(16, texture.getWidth(), fileName); assertEquals(16, texture.getHeight(), fileName); diff --git a/src/test/java/com/mcmoddev/basemetals/content/ContentPolicyTest.java b/src/test/java/com/mcmoddev/basemetals/content/ContentPolicyTest.java index 5270244e..1e848ea2 100644 --- a/src/test/java/com/mcmoddev/basemetals/content/ContentPolicyTest.java +++ b/src/test/java/com/mcmoddev/basemetals/content/ContentPolicyTest.java @@ -19,8 +19,6 @@ class ContentPolicyTest { "lead", "mercury", "mithril", "nickel", "obsidian", "pewter", "platinum", "prismarine", "quartz", "redstone", "silver", "starsteel", "steel", "stone", "tin", "wood", "zinc"); - private static final Set MYTHICAL = set("adamantine", "aquarium", "coldiron", - "mithril", "starsteel"); private static final Set FULL_TOOLS = set("adamantine", "aquarium", "bronze", "coldiron", "copper", "cupronickel", "invar", "mithril", "nickel", "starsteel", "steel", "iron"); @@ -44,6 +42,7 @@ class ContentPolicyTest { @Test void highFantasyAllowsEveryMaterialAndForm() { final ContentPolicy policy = ContentPolicy.forMode(ContentMode.HIGH_FANTASY); + for (final String material : ALL_MATERIALS) { for (final MaterialForm form : MaterialForm.values()) { assertTrue(policy.allows(material, form), material + "/" + form); @@ -52,14 +51,13 @@ void highFantasyAllowsEveryMaterialAndForm() { } @Test - void everyRestrictedModeMaterialAndFormDecisionMatchesTheReviewedMatrix() { - for (final ContentMode mode : Arrays.asList(ContentMode.LOW_FANTASY, ContentMode.REALISM)) { - final ContentPolicy policy = ContentPolicy.forMode(mode); - for (final String material : ALL_MATERIALS) { - for (final MaterialForm form : MaterialForm.values()) { - assertTrue(policy.allows(material, form) == expected(mode, material, form), - mode + " " + material + "/" + form); - } + void lowFantasyMaterialAndFormDecisionsMatchTheReviewedMatrix() { + final ContentPolicy policy = ContentPolicy.forMode(ContentMode.LOW_FANTASY); + + for (final String material : ALL_MATERIALS) { + for (final MaterialForm form : MaterialForm.values()) { + assertTrue(policy.allows(material, form) == expected(material, form), + material + "/" + form); } } } @@ -67,6 +65,7 @@ void everyRestrictedModeMaterialAndFormDecisionMatchesTheReviewedMatrix() { @Test void restrictedModesApplyTheReviewedEquipmentMatrix() { final ContentPolicy low = ContentPolicy.forMode(ContentMode.LOW_FANTASY); + assertFalse(low.allows(MaterialNames.ADAMANTINE, MaterialForm.BOW)); assertTrue(low.allows(MaterialNames.ADAMANTINE, MaterialForm.PICKAXE)); assertFalse(low.allows(MaterialNames.PEWTER, MaterialForm.CHESTPLATE)); @@ -80,31 +79,16 @@ void restrictedModesApplyTheReviewedEquipmentMatrix() { assertFalse(low.allows(MaterialNames.TIN, MaterialForm.GEAR)); } - @Test - void realismRemovesAllNormalAcquisitionForTheFiveMythicalMaterials() { - final ContentPolicy realism = ContentPolicy.forMode(ContentMode.REALISM); - for (final String material : Arrays.asList(MaterialNames.ADAMANTINE, - MaterialNames.AQUARIUM, MaterialNames.COLDIRON, MaterialNames.MITHRIL, - MaterialNames.STARSTEEL)) { - for (final MaterialForm form : MaterialForm.values()) { - assertFalse(realism.allows(material, form), material + "/" + form); - } - assertFalse(realism.defaultsOreEnabled(material)); - } - assertTrue(realism.defaultsOreEnabled(MaterialNames.COPPER)); - } - @Test void mercuryRetainsOnlyTheExplicitProcessingForms() { final ContentPolicy low = ContentPolicy.forMode(ContentMode.LOW_FANTASY); - final ContentPolicy realism = ContentPolicy.forMode(ContentMode.REALISM); + assertTrue(low.allows(MaterialNames.MERCURY, MaterialForm.INGOT)); - assertFalse(realism.allows(MaterialNames.MERCURY, MaterialForm.INGOT)); - assertTrue(realism.allows(MaterialNames.MERCURY, MaterialForm.ORE)); - assertTrue(realism.allows(MaterialNames.MERCURY, MaterialForm.POWDER)); - assertTrue(realism.allows(MaterialNames.MERCURY, MaterialForm.FLUID)); assertFalse(low.allows(MaterialNames.MERCURY, MaterialForm.BLOCK)); - assertFalse(realism.allows(MaterialNames.MERCURY, MaterialForm.SWORD)); + assertTrue(low.allows(MaterialNames.MERCURY, MaterialForm.ORE)); + assertTrue(low.allows(MaterialNames.MERCURY, MaterialForm.POWDER)); + assertTrue(low.allows(MaterialNames.MERCURY, MaterialForm.FLUID)); + assertFalse(low.allows(MaterialNames.MERCURY, MaterialForm.SWORD)); } @Test @@ -115,33 +99,66 @@ void compoundRegistrySuffixesResolveToTheMostSpecificForm() { assertTrue(MaterialForm.fromRegistryPath("nickel_pressure_plate") == MaterialForm.PRESSURE_PLATE); } - private static boolean expected(final ContentMode mode, final String material, - final MaterialForm form) { - if (mode == ContentMode.REALISM && MYTHICAL.contains(material)) return false; - if (form == MaterialForm.OTHER) return !"mercury".equals(material); + private static boolean expected(final String material, final MaterialForm form) { + if (form == MaterialForm.OTHER) { + return !"mercury".equals(material); + } + if (form == MaterialForm.BOW || form == MaterialForm.CROSSBOW - || form == MaterialForm.FISHING_ROD) return false; + || form == MaterialForm.FISHING_ROD) { + return false; + } + if (TOOL_FORMS.contains(form)) { - if (FULL_TOOLS.contains(material)) return true; - if ("silver".equals(material)) return form == MaterialForm.SWORD; - if ("obsidian".equals(material)) return form == MaterialForm.AXE - || form == MaterialForm.SWORD || form == MaterialForm.SCYTHE; - if ("diamond".equals(material)) return form == MaterialForm.CRACKHAMMER - || form == MaterialForm.SCYTHE || form == MaterialForm.SHEARS; - if ("stone".equals(material)) return form == MaterialForm.CRACKHAMMER - || form == MaterialForm.SCYTHE; + if (FULL_TOOLS.contains(material)) { + return true; + } + + if ("silver".equals(material)) { + return form == MaterialForm.SWORD; + } + + if ("obsidian".equals(material)) { + return form == MaterialForm.AXE + || form == MaterialForm.SWORD || form == MaterialForm.SCYTHE; + } + + if ("diamond".equals(material)) { + return form == MaterialForm.CRACKHAMMER + || form == MaterialForm.SCYTHE || form == MaterialForm.SHEARS; + } + + if ("stone".equals(material)) { + return form == MaterialForm.CRACKHAMMER + || form == MaterialForm.SCYTHE; + } + return "wood".equals(material) && form == MaterialForm.CRACKHAMMER; } - if (ARMOR_FORMS.contains(form)) return ARMOR.contains(material); - if (form == MaterialForm.ARROW || form == MaterialForm.BOLT) return AMMO.contains(material); - if (form == MaterialForm.GEAR) return GEARS.contains(material); - if (form == MaterialForm.ANVIL) return "stone".equals(material) - || "steel".equals(material) - || (mode == ContentMode.LOW_FANTASY && "adamantine".equals(material)); - if ("mercury".equals(material)) return form == MaterialForm.ORE - || form == MaterialForm.POWDER || form == MaterialForm.SMALLPOWDER - || form == MaterialForm.FLUID - || (mode == ContentMode.LOW_FANTASY && form == MaterialForm.INGOT); + + if (ARMOR_FORMS.contains(form)) { + return ARMOR.contains(material); + } + + if (form == MaterialForm.ARROW || form == MaterialForm.BOLT) { + return AMMO.contains(material); + } + + if (form == MaterialForm.GEAR) { + return GEARS.contains(material); + } + + if (form == MaterialForm.ANVIL) { + return "stone".equals(material) + || "steel".equals(material) || "adamantine".equals(material); + } + + if ("mercury".equals(material)) { + return form == MaterialForm.ORE + || form == MaterialForm.POWDER || form == MaterialForm.SMALLPOWDER + || form == MaterialForm.FLUID || form == MaterialForm.INGOT; + } + return true; } @@ -151,7 +168,9 @@ private static Set set(final String... values) { private static Set union(final Set first, final Set second) { final Set result = new HashSet<>(first); + result.addAll(second); + return result; } } diff --git a/src/test/java/com/mcmoddev/basemetals/data/DoorRecipeContractTest.java b/src/test/java/com/mcmoddev/basemetals/data/DoorRecipeContractTest.java index d859b933..d5ac8dc3 100644 --- a/src/test/java/com/mcmoddev/basemetals/data/DoorRecipeContractTest.java +++ b/src/test/java/com/mcmoddev/basemetals/data/DoorRecipeContractTest.java @@ -40,6 +40,7 @@ void doorsAndTrapdoorsHaveDistinctCanonicalRecipes() throws IOException { final String fileName = doorPath.getFileName().toString(); final String material = fileName.substring(0, fileName.length() - "_door.json".length()); final Path trapdoorPath = RECIPES.resolve(material + "_trapdoor.json"); + assertTrue(Files.isRegularFile(trapdoorPath), "Missing trapdoor recipe for " + material); @@ -52,23 +53,32 @@ void doorsAndTrapdoorsHaveDistinctCanonicalRecipes() throws IOException { && ingredient(door).equals(ingredient(trapdoor))) { collisions.add(material); } + if (!doorPattern.equals(Arrays.asList("xx", "xx", "xx"))) { invalidDoorShapes.add(material + "=" + String.join("/", doorPattern)); } + final List expectedTrapdoorPattern = "quartz".equals(material) - ? Collections.singletonList("x") : Arrays.asList("xx", "xx"); + ? Collections.singletonList("x") + : Arrays.asList("xx", "xx"); + if (!trapdoorPattern.equals(expectedTrapdoorPattern)) { invalidTrapdoorShapes.add(material + "=" + String.join("/", trapdoorPattern)); } + final String expectedTrapdoorOre = "quartz".equals(material) - ? "blockQuartz" : ingredient(door).get("ore").getAsString(); + ? "blockQuartz" + : ingredient(door).get("ore").getAsString(); + if (!expectedTrapdoorOre.equals(ingredient(trapdoor).get("ore").getAsString())) { invalidTrapdoorIngredients.add(material + "=" + ingredient(trapdoor)); } + if (resultCount(door) != 3 || resultCount(trapdoor) != 1) { invalidYields.add(material + "=door:" + resultCount(door) + ",trapdoor:" + resultCount(trapdoor)); } + pairs++; } } @@ -95,9 +105,11 @@ private static JsonObject read(final Path path) throws IOException { private static List pattern(final JsonObject recipe) { final List result = new ArrayList<>(); final JsonArray pattern = recipe.getAsJsonArray("pattern"); + for (final JsonElement row : pattern) { result.add(row.getAsString()); } + return result; } @@ -107,6 +119,7 @@ private static JsonObject ingredient(final JsonObject recipe) { private static int resultCount(final JsonObject recipe) { final JsonObject result = recipe.getAsJsonObject("result"); + return result.has("count") ? result.get("count").getAsInt() : 1; } } diff --git a/src/test/java/com/mcmoddev/basemetals/data/GameplayAdvancementDataTest.java b/src/test/java/com/mcmoddev/basemetals/data/GameplayAdvancementDataTest.java new file mode 100644 index 00000000..5b655dbe --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/data/GameplayAdvancementDataTest.java @@ -0,0 +1,125 @@ +package com.mcmoddev.basemetals.data; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.junit.jupiter.api.Test; + +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class GameplayAdvancementDataTest { + private static final Path ROOT = Paths.get("build", "generated-resources", + "gameplay-advancements", "assets", "basemetals", "advancements"); + private static final Set IDS = new HashSet<>(Arrays.asList( + "this_is_new", "blocktastic", "geologist", "metallurgy", "aquarium_maker", + "brass_maker", "bronze_maker", "cupronickel_maker", "electrum_maker", + "invar_maker", "mithril_maker", "pewter_maker", "steel_maker", + "angel_of_death", "scuba_diver", "demon_slayer", "juggernaut", "moon_boots")); + + @Test + void restoresEveryHistoricalAchievementWithVisibleNotificationsAndSafeConditions() throws Exception { + try (Stream files = Files.list(ROOT)) { + assertEquals(IDS, files.map(path -> path.getFileName().toString().replace(".json", "")) + .collect(Collectors.toSet())); + } + + for (final String id : IDS) { + final JsonObject json = read(ROOT.resolve(id + ".json")); + final JsonObject display = json.getAsJsonObject("display"); + + assertTrue(display.get("show_toast").getAsBoolean(), id); + assertTrue(display.get("announce_to_chat").getAsBoolean(), id); + assertEquals("achievement." + id, + display.getAsJsonObject("title").get("translate").getAsString()); + assertEquals("achievement." + id + ".desc", + display.getAsJsonObject("description").get("translate").getAsString()); + assertEquals("minecraft:impossible", json.getAsJsonObject("criteria") + .getAsJsonObject("event").get("trigger").getAsString()); + + final JsonObject condition = json.getAsJsonArray("conditions").get(0).getAsJsonObject(); + + assertEquals("basemetals:achievement", condition.get("type").getAsString()); + assertTrue(strings(condition.getAsJsonArray("items")).contains( + display.getAsJsonObject("icon").get("item").getAsString()), id); + + final String parent = json.get("parent").getAsString(); + + if (parent.startsWith("basemetals:")) { + final String parentId = parent.substring("basemetals:".length()); + + assertTrue(IDS.contains(parentId), "Missing parent for " + id); + + final JsonObject parentJson = read(ROOT.resolve(parentId + ".json")); + + assertTrue(strings(condition.getAsJsonArray("items")).contains( + parentJson.getAsJsonObject("display").getAsJsonObject("icon") + .get("item").getAsString()), + "Unsafe disabled parent for " + id); + } + } + + final JsonObject factories = read(Paths.get("src", "main", "resources", "assets", + "basemetals", "advancements", "_factories.json")); + + assertEquals("com.mcmoddev.basemetals.advancement.AchievementCondition", + factories.getAsJsonObject("conditions").get("achievement").getAsString()); + } + + @Test + void everyLocaleContainsAllAchievementNamesAndDescriptions() throws Exception { + final List locales; + + try (Stream files = Files.list(Paths.get("src", "main", "resources", + "assets", "basemetals", "lang"))) { + locales = files.filter(path -> path.toString().endsWith(".lang")).collect(Collectors.toList()); + } + + assertEquals(18, locales.size()); + + for (final Path locale : locales) { + final Properties translations = new Properties(); + + try (Reader reader = Files.newBufferedReader(locale, StandardCharsets.UTF_8)) { + translations.load(reader); + } + + for (final String id : IDS) { + for (final String key : Arrays.asList("achievement." + id, "achievement." + id + ".desc")) { + assertTrue(translations.containsKey(key), locale + " is missing " + key); + assertTrue(!translations.getProperty(key).trim().isEmpty(), locale + " has empty " + key); + } + } + } + } + + private static Set strings(final JsonArray array) { + final Set result = new HashSet<>(); + + for (final JsonElement value : array) { + result.add(value.getAsString()); + } + + return result; + } + + private static JsonObject read(final Path path) throws Exception { + try (Reader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) { + return new JsonParser().parse(reader).getAsJsonObject(); + } + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/data/LootPolicyContractTest.java b/src/test/java/com/mcmoddev/basemetals/data/LootPolicyContractTest.java index 2b90f5a8..26f2de9c 100644 --- a/src/test/java/com/mcmoddev/basemetals/data/LootPolicyContractTest.java +++ b/src/test/java/com/mcmoddev/basemetals/data/LootPolicyContractTest.java @@ -20,6 +20,7 @@ class LootPolicyContractTest { void everyBaseMetalsAuxiliaryLootEntryUsesTheContentPolicyCondition() throws Exception { final Path root = Paths.get("src", "main", "resources", "assets", "basemetals", "alt", "chests"); final AtomicInteger checked = new AtomicInteger(); + try (java.util.stream.Stream files = Files.list(root)) { for (final Path file : (Iterable) files.filter(path -> path.toString().endsWith(".json"))::iterator) { try (Reader reader = Files.newBufferedReader(file)) { @@ -27,6 +28,7 @@ void everyBaseMetalsAuxiliaryLootEntryUsesTheContentPolicyCondition() throws Exc } } } + assertTrue(checked.get() > 500, "Expected the complete legacy auxiliary-loot inventory"); } @@ -36,29 +38,39 @@ private static void visit(final JsonElement element, final Path file, for (final JsonElement child : element.getAsJsonArray()) { visit(child, file, checked); } + return; } + if (!element.isJsonObject()) { return; } + final JsonObject object = element.getAsJsonObject(); + if (object.has("type") && "item".equals(object.get("type").getAsString()) && object.has("name") && object.get("name").getAsString().startsWith("basemetals:")) { final JsonArray conditions = object.getAsJsonArray("conditions"); + assertTrue(conditions != null, file + " " + object.get("name")); + int matches = 0; + for (final JsonElement condition : conditions) { final JsonObject value = condition.getAsJsonObject(); + if (value.has("condition") && "basemetals:content_policy".equals(value.get("condition").getAsString())) { matches++; assertEquals(object.get("name").getAsString(), value.get("item").getAsString()); } } + assertEquals(1, matches, file + " " + object.get("name")); checked.incrementAndGet(); } + for (final java.util.Map.Entry child : object.entrySet()) { visit(child.getValue(), file, checked); } diff --git a/src/test/java/com/mcmoddev/basemetals/data/OreSpawnProviderContractTest.java b/src/test/java/com/mcmoddev/basemetals/data/OreSpawnProviderContractTest.java index 38f8eef6..1439acd8 100644 --- a/src/test/java/com/mcmoddev/basemetals/data/OreSpawnProviderContractTest.java +++ b/src/test/java/com/mcmoddev/basemetals/data/OreSpawnProviderContractTest.java @@ -15,8 +15,6 @@ import org.junit.jupiter.api.Test; -import com.mcmoddev.basemetals.content.ContentMode; -import com.mcmoddev.basemetals.content.ContentPolicy; import com.mcmoddev.basemetals.worldgen.BaseMetalsWorldgenProvider; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -30,28 +28,25 @@ class OreSpawnProviderContractTest { @Test void nativeProviderMatchesTheStableTranslatedContract() { - final JsonObject provider = BaseMetalsWorldgenProvider - .build(ContentPolicy.forMode(ContentMode.HIGH_FANTASY)).toJson(); + final JsonObject provider = BaseMetalsWorldgenProvider.build().toJson(); + assertProviderIdentity(provider); final JsonObject ores = provider.getAsJsonObject("ores"); + assertEquals(expectedRules().keySet(), keys(ores)); + for (final Map.Entry expected : expectedRules().entrySet()) { assertRule(ores.getAsJsonObject(expected.getKey()), expected.getKey(), expected.getValue(), true); } } @Test - void contentModesOnlyChangeTheThreeFreshWorldFantasyDefaults() { - final JsonObject high = provider(ContentMode.HIGH_FANTASY); - final JsonObject low = provider(ContentMode.LOW_FANTASY); - final JsonObject realism = provider(ContentMode.REALISM); + void allElevenOresAreEnabledIndependentOfContentMode() { + final JsonObject provider = BaseMetalsWorldgenProvider.build().toJson(); + for (final String id : expectedRules().keySet()) { - assertTrue(high.getAsJsonObject("ores").getAsJsonObject(id).get("enabled").getAsBoolean(), id); - assertTrue(low.getAsJsonObject("ores").getAsJsonObject(id).get("enabled").getAsBoolean(), id); - final boolean mythical = id.contains("adamantine") || id.contains("coldiron") - || id.contains("starsteel"); - assertEquals(!mythical, realism.getAsJsonObject("ores").getAsJsonObject(id) + assertTrue(provider.getAsJsonObject("ores").getAsJsonObject(id) .get("enabled").getAsBoolean(), id); } } @@ -59,10 +54,13 @@ void contentModesOnlyChangeTheThreeFreshWorldFantasyDefaults() { @Test void disabledExampleRetainsEveryRuleButDisablesAllOfThem() throws IOException { final JsonObject example = read(DISABLED_EXAMPLE); + assertProviderIdentity(example); final JsonObject ores = example.getAsJsonObject("ores"); + assertEquals(expectedRules().keySet(), keys(ores)); + for (final Map.Entry expected : expectedRules().entrySet()) { assertRule(ores.getAsJsonObject(expected.getKey()), expected.getKey(), expected.getValue(), false); } @@ -74,6 +72,7 @@ private static void assertProviderIdentity(final JsonObject provider) { assertEquals(2, provider.get("provider_revision").getAsInt()); assertTrue(provider.get("merge_new_entries_into_existing_worlds").getAsBoolean()); assertTrue(provider.getAsJsonObject("rocks").entrySet().isEmpty()); + for (final String section : Arrays.asList("fluid_deposits", "geomes", "biome_rules", "terrain_dimensions", "biome_palettes", "dimension_materials", "templates")) { assertTrue(provider.getAsJsonObject(section).entrySet().isEmpty(), section + " must remain empty"); @@ -88,6 +87,7 @@ private static void assertRule(final JsonObject rule, final String id, assertFalse(rule.get("retrogen").getAsBoolean(), id); final JsonArray outputs = rule.getAsJsonArray("outputs"); + assertEquals(1, outputs.size(), id); assertEquals("basemetals:" + expected.ore, outputs.get(0).getAsJsonObject().get("block").getAsString(), id); @@ -96,9 +96,11 @@ private static void assertRule(final JsonObject rule, final String id, assertEquals(2048, outputs.get(0).getAsJsonObject().get("max_y").getAsInt(), id); final String containerName = expected.dimension.startsWith("minecraft:") - ? "dimensions" : "dimension_selectors"; + ? "dimensions" + : "dimension_selectors"; final JsonObject settings = rule.getAsJsonObject(containerName) .getAsJsonObject(expected.dimension); + assertTrue(settings.get("enabled").getAsBoolean(), id); assertEquals(expected.minY, settings.get("min_y").getAsInt(), id); assertEquals(expected.maxY, settings.get("max_y").getAsInt(), id); @@ -114,19 +116,18 @@ private static void assertRule(final JsonObject rule, final String id, assertEquals(8, settings.get("node_size").getAsInt(), id); assertEquals(Arrays.asList("minecraft:stone", "minecraft:netherrack", "minecraft:end_stone"), weightedIds(settings.getAsJsonArray("host_blocks"), "block"), id); + for (final String empty : Arrays.asList("host_tags", "host_families", "biome_ids", "excluded_biome_ids", "biome_dictionary", "excluded_biome_dictionary")) { assertTrue(settings.getAsJsonArray(empty).size() == 0, id + " " + empty); } - assertTrue(settings.getAsJsonObject("geomes").entrySet().isEmpty(), id); - } - private static JsonObject provider(final ContentMode mode) { - return BaseMetalsWorldgenProvider.build(ContentPolicy.forMode(mode)).toJson(); + assertTrue(settings.getAsJsonObject("geomes").entrySet().isEmpty(), id); } private static Map expectedRules() { final Map result = new LinkedHashMap<>(); + result.put("basemetals:legacy/coldiron_ore", new Rule("coldiron_ore", "minecraft:the_nether", 0, 127, 5.0D)); result.put("basemetals:legacy/adamantine_ore", @@ -149,36 +150,45 @@ private static Map expectedRules() { new Rule("nickel_ore", "orespawn:all_except_nether_end", 32, 95, 1.0D)); result.put("basemetals:legacy/platinum_ore", new Rule("platinum_ore", "orespawn:all_except_nether_end", 1, 31, 0.125D)); + return Collections.unmodifiableMap(result); } private static java.util.List strings(final JsonArray values) { final java.util.List result = new java.util.ArrayList<>(); + for (final JsonElement value : values) { result.add(value.getAsString()); } + return result; } private static java.util.List weightedIds(final JsonArray values, final String key) { final java.util.List result = new java.util.ArrayList<>(); + for (final JsonElement value : values) { - result.add(value.isJsonPrimitive() ? value.getAsString() + result.add(value.isJsonPrimitive() + ? value.getAsString() : value.getAsJsonObject().get(key).getAsString()); } + return result; } private static java.util.Set keys(final JsonObject object) { final java.util.Set result = new java.util.LinkedHashSet<>(); + for (final Map.Entry entry : object.entrySet()) { result.add(entry.getKey()); } + return result; } private static JsonObject read(final Path path) throws IOException { assertTrue(Files.isRegularFile(path), "Missing JSON contract " + path); + try (Reader reader = Files.newBufferedReader(path)) { return new JsonParser().parse(reader).getAsJsonObject(); } diff --git a/src/test/java/com/mcmoddev/basemetals/data/RailRecipeAdvancementTest.java b/src/test/java/com/mcmoddev/basemetals/data/RailRecipeAdvancementTest.java index 6610c76c..e3b6e31d 100644 --- a/src/test/java/com/mcmoddev/basemetals/data/RailRecipeAdvancementTest.java +++ b/src/test/java/com/mcmoddev/basemetals/data/RailRecipeAdvancementTest.java @@ -31,21 +31,26 @@ void ironOrSteelUnlocksBothRailRecipes() throws IOException { "Missing recipe-book advancement " + ADVANCEMENT); final JsonObject advancement = read(ADVANCEMENT); + assertEquals("minecraft:recipes/root", advancement.get("parent").getAsString()); assertEquals(setOf("minecraft:rail", "basemetals:rail"), strings(advancement.getAsJsonObject("rewards").getAsJsonArray("recipes"))); final JsonObject criteria = advancement.getAsJsonObject("criteria"); + assertInventoryCriterion(criteria.getAsJsonObject("has_iron_ingot"), "minecraft:iron_ingot"); assertInventoryCriterion(criteria.getAsJsonObject("has_steel_ingot"), "basemetals:steel_ingot"); + final JsonObject unlocked = criteria.getAsJsonObject("has_the_recipe"); + assertEquals("minecraft:recipe_unlocked", unlocked.get("trigger").getAsString()); assertEquals("basemetals:rail", unlocked.getAsJsonObject("conditions").get("recipe").getAsString()); final JsonArray requirements = advancement.getAsJsonArray("requirements"); + assertEquals(1, requirements.size(), "The three discovery paths must be alternatives"); assertEquals(setOf("has_iron_ingot", "has_steel_ingot", "has_the_recipe"), strings(requirements.get(0).getAsJsonArray())); @@ -53,7 +58,9 @@ void ironOrSteelUnlocksBothRailRecipes() throws IOException { private static void assertInventoryCriterion(final JsonObject criterion, final String item) { assertEquals("minecraft:inventory_changed", criterion.get("trigger").getAsString()); + final JsonArray items = criterion.getAsJsonObject("conditions").getAsJsonArray("items"); + assertEquals(1, items.size()); assertEquals(item, items.get(0).getAsJsonObject().get("item").getAsString()); } @@ -66,9 +73,11 @@ private static JsonObject read(final Path path) throws IOException { private static Set strings(final JsonArray values) { final Set result = new HashSet<>(); + for (final JsonElement value : values) { result.add(value.getAsString()); } + return result; } diff --git a/src/test/java/com/mcmoddev/basemetals/data/RecipeBookAdvancementCoverageTest.java b/src/test/java/com/mcmoddev/basemetals/data/RecipeBookAdvancementCoverageTest.java new file mode 100644 index 00000000..845f5ffc --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/data/RecipeBookAdvancementCoverageTest.java @@ -0,0 +1,243 @@ +package com.mcmoddev.basemetals.data; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.io.Reader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +class RecipeBookAdvancementCoverageTest { + + private static final Path RECIPES = Paths.get( + "src", "main", "resources", "assets", "basemetals", "recipes"); + private static final Path ADVANCEMENTS = Paths.get( + "build", "generated-resources", "recipe-advancements", "assets", + "basemetals", "advancements", "recipes", "materials"); + private static final Path FACTORIES = Paths.get( + "src", "main", "resources", "assets", "basemetals", "advancements", + "_factories.json"); + + private static final Map MATERIAL_ORES = materialOres(); + private static final Set GENERIC_STEEL_RECIPES = new LinkedHashSet<>(Arrays.asList( + "activator_rail", "detector_rail", "flint_and_steel", "human_detector", + "minecart", "piston", "rail", "tripwire_hook")); + + @Test + void everyRecipeHasAConditionAwareMaterialUnlock() throws IOException { + assertTrue(Files.isRegularFile(FACTORIES), + "Recipe advancements need their MMDLib condition factory"); + + final JsonObject factories = read(FACTORIES); + + assertEquals("com.mcmoddev.lib.recipe.conditions.ConditionEnabled", + factories.getAsJsonObject("conditions").get("enabled").getAsString()); + assertEquals("com.mcmoddev.lib.recipe.conditions.HammerEnabled", + factories.getAsJsonObject("conditions").get("hammer").getAsString()); + assertEquals("com.mcmoddev.lib.recipe.conditions.PlateRepairEnabled", + factories.getAsJsonObject("conditions").get("plate").getAsString()); + + final Set expectedAdvancements = new LinkedHashSet<>(); + + try (Stream stream = Files.list(RECIPES)) { + for (final Path recipePath : stream.filter(path -> path.toString().endsWith(".json")) + .filter(path -> !"_factories.json".equals(path.getFileName().toString())) + .filter(path -> !path.getFileName().toString().endsWith("_plate_repair.json")) + .sorted().collect(Collectors.toList())) { + final String recipeName = withoutExtension(recipePath.getFileName().toString()); + final String material = materialFor(recipeName); + + assertNotNull(material, "No recipe-book discovery material for " + recipeName); + + final Path advancementPath = ADVANCEMENTS.resolve(material) + .resolve(recipeName + ".json"); + + expectedAdvancements.add(advancementPath.normalize()); + assertTrue(Files.isRegularFile(advancementPath), + "Missing generated recipe advancement " + advancementPath); + assertAdvancement(recipePath, advancementPath, recipeName, material); + } + } + + final Set actualAdvancements; + + try (Stream stream = Files.walk(ADVANCEMENTS)) { + actualAdvancements = stream.filter(Files::isRegularFile) + .filter(path -> path.toString().endsWith(".json")) + .map(Path::normalize).collect(Collectors.toCollection(LinkedHashSet::new)); + } + + assertEquals(expectedAdvancements, actualAdvancements, + "Generated recipe advancements must exactly follow the recipe catalogue"); + } + + private static void assertAdvancement(final Path recipePath, final Path advancementPath, + final String recipeName, final String material) throws IOException { + final JsonObject recipe = read(recipePath); + final JsonObject advancement = read(advancementPath); + + assertEquals("minecraft:recipes/root", advancement.get("parent").getAsString()); + + final JsonArray rewards = advancement.getAsJsonObject("rewards").getAsJsonArray("recipes"); + + assertEquals(1, rewards.size()); + assertEquals("basemetals:" + recipeName, rewards.get(0).getAsString()); + + final JsonObject criteria = advancement.getAsJsonObject("criteria"); + final JsonObject acquired = criteria.getAsJsonObject("has_material"); + + assertEquals("minecraft:inventory_changed", acquired.get("trigger").getAsString()); + + final JsonObject predicate = acquired.getAsJsonObject("conditions") + .getAsJsonArray("items").get(0).getAsJsonObject(); + + assertEquals("forge:ore_dict", predicate.get("type").getAsString()); + assertEquals(MATERIAL_ORES.get(material), predicate.get("ore").getAsString()); + + final JsonObject unlocked = criteria.getAsJsonObject("has_the_recipe"); + + assertEquals("minecraft:recipe_unlocked", unlocked.get("trigger").getAsString()); + assertEquals("basemetals:" + recipeName, + unlocked.getAsJsonObject("conditions").get("recipe").getAsString()); + + final JsonArray requirements = advancement.getAsJsonArray("requirements"); + + assertEquals(1, requirements.size()); + assertEquals(new LinkedHashSet<>(Arrays.asList("has_material", "has_the_recipe")), + strings(requirements.get(0).getAsJsonArray())); + + if (recipe.has("conditions")) { + assertEquals(advancementConditions(recipe.get("conditions")), + advancement.get("conditions"), + "Advancement conditions must preserve " + recipeName); + } else { + assertFalse(advancement.has("conditions"), + "Unconditional recipe gained conditions: " + recipeName); + } + } + + private static JsonElement advancementConditions(final JsonElement value) { + if (value.isJsonArray()) { + final JsonArray result = new JsonArray(); + + for (final JsonElement child : value.getAsJsonArray()) { + result.add(advancementConditions(child)); + } + + return result; + } + + if (value.isJsonObject()) { + final JsonObject result = new JsonObject(); + + for (final Map.Entry entry : value.getAsJsonObject().entrySet()) { + JsonElement child = entry.getValue(); + + if ("type".equals(entry.getKey()) && child.isJsonPrimitive() + && child.getAsString().startsWith("mmdlib:")) { + child = new com.google.gson.JsonPrimitive("basemetals:" + + child.getAsString().substring("mmdlib:".length())); + } else { + child = advancementConditions(child); + } + + result.add(entry.getKey(), child); + } + + return result; + } + + return value; + } + + private static String materialFor(final String recipeName) { + if (GENERIC_STEEL_RECIPES.contains(recipeName)) { + return "steel"; + } + + for (final String material : MATERIAL_ORES.keySet()) { + if (recipeName.equals(material) || recipeName.startsWith(material + "_")) { + return material; + } + } + + return null; + } + + private static String withoutExtension(final String fileName) { + return fileName.substring(0, fileName.length() - ".json".length()); + } + + private static JsonObject read(final Path path) throws IOException { + try (Reader reader = Files.newBufferedReader(path)) { + return new JsonParser().parse(reader).getAsJsonObject(); + } + } + + private static Set strings(final JsonArray values) { + final Set result = new LinkedHashSet<>(); + + for (final JsonElement value : values) { + result.add(value.getAsString()); + } + + return result; + } + + private static Map materialOres() { + final Map ores = new LinkedHashMap<>(); + + ores.put("adamantine", "ingotAdamantine"); + ores.put("antimony", "ingotAntimony"); + ores.put("aquarium", "ingotAquarium"); + ores.put("bismuth", "ingotBismuth"); + ores.put("brass", "ingotBrass"); + ores.put("bronze", "ingotBronze"); + ores.put("charcoal", "charcoal"); + ores.put("coal", "coal"); + ores.put("coldiron", "ingotColdiron"); + ores.put("copper", "ingotCopper"); + ores.put("cupronickel", "ingotCupronickel"); + ores.put("diamond", "gemDiamond"); + ores.put("electrum", "ingotElectrum"); + ores.put("emerald", "gemEmerald"); + ores.put("gold", "ingotGold"); + ores.put("invar", "ingotInvar"); + ores.put("iron", "ingotIron"); + ores.put("lead", "ingotLead"); + ores.put("mithril", "ingotMithril"); + ores.put("nickel", "ingotNickel"); + ores.put("obsidian", "ingotObsidian"); + ores.put("pewter", "ingotPewter"); + ores.put("platinum", "ingotPlatinum"); + ores.put("quartz", "gemQuartz"); + ores.put("redstone", "dustRedstone"); + ores.put("silver", "ingotSilver"); + ores.put("starsteel", "ingotStarsteel"); + ores.put("steel", "ingotSteel"); + ores.put("stone", "stone"); + ores.put("tin", "ingotTin"); + ores.put("wood", "logWood"); + ores.put("zinc", "ingotZinc"); + + return ores; + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/data/RecipeBookGroupingTest.java b/src/test/java/com/mcmoddev/basemetals/data/RecipeBookGroupingTest.java new file mode 100644 index 00000000..40052601 --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/data/RecipeBookGroupingTest.java @@ -0,0 +1,67 @@ +package com.mcmoddev.basemetals.data; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.io.Reader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +class RecipeBookGroupingTest { + + private static final Path RECIPES = Paths.get( + "src", "main", "resources", "assets", "basemetals", "recipes"); + + @Test + void eachCraftedOutputHasItsOwnRecipeBookCell() throws IOException { + int checked = 0; + + try (Stream stream = Files.list(RECIPES)) { + final List recipes = stream + .filter(path -> path.toString().endsWith(".json")) + .filter(path -> !"_factories.json".equals(path.getFileName().toString())) + .sorted().collect(Collectors.toList()); + + for (final Path recipePath : recipes) { + final JsonObject recipe = read(recipePath); + + if (!recipe.has("result") || !recipe.get("result").isJsonObject()) { + continue; + } + + final JsonObject result = recipe.getAsJsonObject("result"); + + if (!result.has("item")) { + continue; + } + + final String output = result.get("item").getAsString(); + + assertTrue(recipe.has("group"), + "Recipe has no recipe-book group: " + recipePath.getFileName()); + assertEquals(output, recipe.get("group").getAsString(), + "Recipe-book group must match its crafted output: " + + recipePath.getFileName()); + checked++; + } + } + + assertTrue(checked > 1000, "Expected to check the complete recipe catalogue"); + } + + private static JsonObject read(final Path path) throws IOException { + try (Reader reader = Files.newBufferedReader(path)) { + return new JsonParser().parse(reader).getAsJsonObject(); + } + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/network/ContentModeNetworkTest.java b/src/test/java/com/mcmoddev/basemetals/network/ContentModeNetworkTest.java index 256c24b9..0af5dc02 100644 --- a/src/test/java/com/mcmoddev/basemetals/network/ContentModeNetworkTest.java +++ b/src/test/java/com/mcmoddev/basemetals/network/ContentModeNetworkTest.java @@ -14,8 +14,11 @@ class ContentModeNetworkTest { void everyStableModeRoundTripsOverTheHandshake() { for (final ContentMode mode : ContentMode.values()) { final ByteBuf buffer = Unpooled.buffer(); + new ContentModeMessage(mode).toBytes(buffer); + final ContentModeMessage decoded = new ContentModeMessage(); + decoded.fromBytes(buffer); assertTrue(decoded.hasValidMode()); assertEquals(mode, decoded.mode()); @@ -27,7 +30,12 @@ void everyStableModeRoundTripsOverTheHandshake() { void genuineModeDifferencesAreRejectedByTheComparisonContract() { assertFalse(ContentModeNetwork.modesMatch( ContentMode.HIGH_FANTASY, ContentMode.LOW_FANTASY)); - assertFalse(ContentModeNetwork.modesMatch( - ContentMode.LOW_FANTASY, ContentMode.REALISM)); + } + + @Test + void unrecognizedModesUseTheHighFantasyFallback() { + assertFalse(ContentMode.isValidSerializedName("not_a_mode")); + assertEquals(ContentMode.HIGH_FANTASY, ContentMode.fromSerializedName("not_a_mode")); + assertEquals(ContentMode.HIGH_FANTASY, ContentMode.fromSerializedName(null)); } } diff --git a/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsAdvancementRuntimeProbe.java b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsAdvancementRuntimeProbe.java new file mode 100644 index 00000000..7261bf03 --- /dev/null +++ b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsAdvancementRuntimeProbe.java @@ -0,0 +1,339 @@ +package com.mcmoddev.basemetals.test; + +import com.mojang.authlib.GameProfile; +import com.mcmoddev.lib.util.Config.Options; +import net.minecraft.advancements.Advancement; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.EntityEquipmentSlot; +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.network.NetHandlerPlayServer; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.EnumPacketDirection; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.management.PlayerInteractionManager; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.WorldServer; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.BlockSnapshot; +import net.minecraftforge.event.world.BlockEvent; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventHandler; +import net.minecraftforge.fml.common.event.FMLServerStartedEvent; +import net.minecraftforge.fml.common.gameevent.PlayerEvent.ItemCraftedEvent; +import net.minecraftforge.fml.common.gameevent.PlayerEvent.ItemSmeltedEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +import java.io.File; +import java.io.FileOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.UUID; + +/** Checks achievement awards and saved progress in a running Forge server. */ +@Mod( + modid = "basemetals_advancement_probe", + version = "1", + dependencies = "required-after:basemetals", + acceptedMinecraftVersions = "[1.12.2]") +public final class BaseMetalsAdvancementRuntimeProbe { + private static final List ALLOYS = Arrays.asList("aquarium", "brass", "bronze", + "cupronickel", "electrum", "invar", "mithril", "pewter", "steel"); + private static final List GENERAL = Arrays.asList("this_is_new", "blocktastic", + "geologist", "metallurgy", "angel_of_death", "scuba_diver", "demon_slayer", + "juggernaut", "moon_boots"); + private MinecraftServer server; + private String profile; + private boolean reload; + private int checks; + + @EventHandler + public void serverStarted(final FMLServerStartedEvent event) throws Exception { + server = FMLCommonHandler.instance().getMinecraftServerInstance(); + profile = System.getProperty("basemetals.advancementProbe.profile"); + reload = "Reload".equals(System.getProperty("basemetals.advancementProbe.phase")); + + for (final String id : GENERAL) { + checkDefinition(id); + } + + for (final String alloy : ALLOYS) { + checkDefinition(alloy + "_maker"); + } + + if (!"Disabled".equals(profile)) { + verifyCraftingAndSmelting(); + verifyEquipment(); + verifyBlockPlacement(); + + final boolean enabled = Options.enableAchievements(); + + try { + Options.setEnableAchievements(false); + + final EntityPlayerMP player = player("disabled-events"); + + equip(player, "adamantine", 4); + tick(player); + require(!done(player, "juggernaut"), "Disabled achievements were awarded"); + } finally { + Options.setEnableAchievements(enabled); + } + } + + final Properties result = new Properties(); + + result.setProperty("profile", profile); + result.setProperty("phase", System.getProperty("basemetals.advancementProbe.phase")); + result.setProperty("checks", Integer.toString(checks)); + result.setProperty("passed", "true"); + + try (FileOutputStream output = new FileOutputStream( + new File(System.getProperty("basemetals.advancementProbe.marker")))) { + result.store(output, "Base Metals gameplay advancement checks"); + } + + server.initiateShutdown(); + } + + private void checkDefinition(final String id) { + final Advancement advancement = advancement(id); + final boolean missing = "Disabled".equals(profile) + || ("MaterialOff".equals(profile) + && ("mithril_maker".equals(id) || "angel_of_death".equals(id))); + + require((advancement == null) == missing, "Unexpected advancement availability: " + id); + + if (!missing) { + require(advancement.getDisplay() != null, id + " has no achievement display"); + } + } + + private void verifyCraftingAndSmelting() { + for (final String alloy : ALLOYS) { + if ("MaterialOff".equals(profile) && "mithril".equals(alloy)) { + continue; + } + + final EntityPlayerMP player = player(alloy + "_maker"); + + prepare(player, alloy + "_maker"); + MinecraftForge.EVENT_BUS.post(new ItemSmeltedEvent(player, stack(alloy + "_ingot"))); + require(done(player, alloy + "_maker"), alloy + " smelting did not award its advancement"); + require(done(player, "this_is_new"), "Base Metals ingot did not award This is new"); + player.getAdvancements().save(); + } + + for (final String form : Arrays.asList("bronze_blend", "bronze_smallblend", "stone_crackhammer")) { + final String id = form.endsWith("crackhammer") ? "geologist" : "metallurgy"; + final EntityPlayerMP player = player(form); + + prepare(player, id); + + final InventoryCrafting grid = new InventoryCrafting(new Container() { + @Override + public boolean canInteractWith(final net.minecraft.entity.player.EntityPlayer p) { + return true; + } + }, 3, 3); + + MinecraftForge.EVENT_BUS.post(new ItemCraftedEvent(player, stack(form), grid)); + require(done(player, id), form + " crafting did not award " + id); + player.getAdvancements().save(); + } + + final EntityPlayerMP vanilla = player("vanilla"); + + MinecraftForge.EVENT_BUS.post(new ItemSmeltedEvent(vanilla, new ItemStack(Items.IRON_INGOT))); + require(!done(vanilla, "this_is_new"), "Vanilla ingot awarded Base Metals advancement"); + } + + private void verifyEquipment() { + for (final String material : Arrays.asList("adamantine", "coldiron", "mithril")) { + if ("MaterialOff".equals(profile) && "mithril".equals(material)) { + continue; + } + + final String id = "adamantine".equals(material) + ? "juggernaut" + : "coldiron".equals(material) ? "demon_slayer" : "angel_of_death"; + final EntityPlayerMP player = player(id); + + prepare(player, id); + equip(player, material, 3); + player.setHeldItem(EnumHand.MAIN_HAND, stack(material + "_sword")); + tick(player); + require(!done(player, id), "Three armour pieces awarded " + id); + equip(player, material, 4); + player.setItemStackToSlot(EntityEquipmentSlot.HEAD, stack("copper_helmet")); + tick(player); + require(!done(player, id), "Mixed armour awarded " + id); + equip(player, material, 4); + + if (!"adamantine".equals(material)) { + player.setHeldItem(EnumHand.MAIN_HAND, stack("copper_sword")); + tick(player); + require(!done(player, id), "Wrong sword awarded " + id); + player.setHeldItem(EnumHand.MAIN_HAND, stack(material + "_sword")); + } else { + player.setHeldItem(EnumHand.MAIN_HAND, ItemStack.EMPTY); + } + + tick(player); + require(done(player, id), "Full equipment did not award " + id); + tick(player); + require(done(player, id), "Repeating the tick lost " + id); + player.getAdvancements().save(); + } + + final EntityPlayerMP boots = player("moon_boots"); + + prepare(boots, "moon_boots"); + boots.setItemStackToSlot(EntityEquipmentSlot.FEET, stack("copper_boots")); + tick(boots); + require(!done(boots, "moon_boots"), "Ordinary boots awarded Moon Walker"); + boots.setItemStackToSlot(EntityEquipmentSlot.FEET, stack("starsteel_boots")); + tick(boots); + require(done(boots, "moon_boots"), "Starsteel boots did not award Moon Walker"); + boots.getAdvancements().save(); + + final EntityPlayerMP scuba = player("scuba_diver"); + + prepare(scuba, "scuba_diver"); + equip(scuba, "aquarium", 4); + + final WorldServer world = server.getWorld(0); + final BlockPos feet = new BlockPos(8, 200, 8); + final IBlockState oldFeet = world.getBlockState(feet); + final IBlockState oldHead = world.getBlockState(feet.up()); + + try { + world.setBlockState(feet, Blocks.AIR.getDefaultState(), 2); + world.setBlockState(feet.up(), Blocks.AIR.getDefaultState(), 2); + scuba.setPosition(8.5D, 200.0D, 8.5D); + tick(scuba); + require(!done(scuba, "scuba_diver"), "Dry aquarium armour awarded SCUBA Diver"); + world.setBlockState(feet, Blocks.WATER.getDefaultState(), 2); + world.setBlockState(feet.up(), Blocks.WATER.getDefaultState(), 2); + scuba.setItemStackToSlot(EntityEquipmentSlot.HEAD, ItemStack.EMPTY); + tick(scuba); + require(!done(scuba, "scuba_diver"), "Incomplete submerged suit awarded SCUBA Diver"); + equip(scuba, "aquarium", 4); + tick(scuba); + require(done(scuba, "scuba_diver"), "Submerged aquarium suit did not award SCUBA Diver"); + scuba.getAdvancements().save(); + } finally { + world.setBlockState(feet, oldFeet, 2); + world.setBlockState(feet.up(), oldHead, 2); + } + } + + private void verifyBlockPlacement() { + final EntityPlayerMP player = player("blocktastic"); + + prepare(player, "blocktastic"); + + final WorldServer world = server.getWorld(0); + final BlockPos pos = new BlockPos(9, 200, 9); + final IBlockState original = world.getBlockState(pos); + + try { + world.setBlockState(pos, Blocks.IRON_BLOCK.getDefaultState(), 2); + place(player, pos); + require(!done(player, "blocktastic"), "Vanilla iron block awarded Blocktastic"); + world.setBlockState(pos, Block.REGISTRY.getObject( + new ResourceLocation("basemetals:copper_block")).getDefaultState(), 2); + + final BlockEvent.EntityPlaceEvent cancelled = placeEvent(player, pos); + + cancelled.setCanceled(true); + MinecraftForge.EVENT_BUS.post(cancelled); + require(!done(player, "blocktastic"), "Cancelled placement awarded Blocktastic"); + place(player, pos); + require(done(player, "blocktastic"), "Copper storage block did not award Blocktastic"); + player.getAdvancements().save(); + } finally { + world.setBlockState(pos, original, 2); + } + } + + private void place(final EntityPlayerMP player, final BlockPos pos) { + MinecraftForge.EVENT_BUS.post(placeEvent(player, pos)); + } + + private BlockEvent.EntityPlaceEvent placeEvent(final EntityPlayerMP player, final BlockPos pos) { + return new BlockEvent.EntityPlaceEvent(BlockSnapshot.getBlockSnapshot(server.getWorld(0), pos), + Blocks.AIR.getDefaultState(), player); + } + + private void equip(final EntityPlayerMP player, final String material, final int count) { + final EntityEquipmentSlot[] slots = {EntityEquipmentSlot.FEET, EntityEquipmentSlot.LEGS, + EntityEquipmentSlot.CHEST, EntityEquipmentSlot.HEAD}; + final String[] forms = {"boots", "leggings", "chestplate", "helmet"}; + + for (int index = 0; index < slots.length; index++) { + player.setItemStackToSlot(slots[index], index < count + ? stack(material + "_" + forms[index]) + : ItemStack.EMPTY); + } + } + + private void tick(final EntityPlayerMP player) { + player.ticksExisted = 20; + MinecraftForge.EVENT_BUS.post(new TickEvent.PlayerTickEvent(TickEvent.Phase.END, player)); + } + + private EntityPlayerMP player(final String name) { + final UUID id = UUID.nameUUIDFromBytes((profile + name).getBytes(StandardCharsets.UTF_8)); + final EntityPlayerMP player = new EntityPlayerMP(server, server.getWorld(0), + new GameProfile(id, name), new PlayerInteractionManager(server.getWorld(0))); + + player.connection = new NetHandlerPlayServer(server, + new NetworkManager(EnumPacketDirection.SERVERBOUND), player); + + return player; + } + + private void prepare(final EntityPlayerMP player, final String id) { + if (reload) { + require(done(player, id), "Reload lost saved advancement " + id); + } + + player.getAdvancements().revokeCriterion(advancement(id), "event"); + } + + private Advancement advancement(final String id) { + return server.getAdvancementManager().getAdvancement(new ResourceLocation("basemetals", id)); + } + + private boolean done(final EntityPlayerMP player, final String id) { + return player.getAdvancements().getProgress(advancement(id)).isDone(); + } + + private ItemStack stack(final String name) { + final ResourceLocation id = new ResourceLocation("basemetals", name); + + require(Item.REGISTRY.containsKey(id), "Missing fixture item " + id); + + return new ItemStack(Item.REGISTRY.getObject(id)); + } + + private void require(final boolean condition, final String message) { + checks++; + + if (!condition) { + throw new IllegalStateException(message); + } + } +} diff --git a/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsClientConfigRuntimeProbe.java b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsClientConfigRuntimeProbe.java index c8f72296..9a19ab36 100644 --- a/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsClientConfigRuntimeProbe.java +++ b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsClientConfigRuntimeProbe.java @@ -1,11 +1,21 @@ package com.mcmoddev.basemetals.test; import com.mcmoddev.basemetals.client.config.BaseMetalsConfigScreen; +import com.mcmoddev.basemetals.client.config.BaseMetalsGuiFactory; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiMainMenu; import net.minecraft.client.gui.GuiScreen; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.client.FMLClientHandler; +import net.minecraftforge.fml.client.GuiModList; +import net.minecraftforge.fml.client.IModGuiFactory; import net.minecraftforge.fml.client.config.GuiConfig; +import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventHandler; import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; import zone.moddev.mc.orespawn.api.client.WorldSettingsExtension; import zone.moddev.mc.orespawn.api.client.WorldSettingsExtensionRegistry; @@ -16,7 +26,7 @@ import java.util.Properties; import java.util.stream.Collectors; -/** Test-only client probe. This class is packaged separately and never enters the release jar. */ +/** Checks both configuration-screen entry points in a running client. */ @Mod( modid = BaseMetalsClientConfigRuntimeProbe.MODID, name = "Base Metals Client Configuration Probe", @@ -26,6 +36,8 @@ acceptedMinecraftVersions = "[1.12.2]") public final class BaseMetalsClientConfigRuntimeProbe { public static final String MODID = "basemetals_client_config_probe"; + private final Properties result = new Properties(); + private boolean checkedModsButton; @EventHandler public void init(final FMLInitializationEvent event) throws IOException { @@ -33,42 +45,93 @@ public void init(final FMLInitializationEvent event) throws IOException { .stream() .filter(extension -> "basemetals".equals(extension.id().getNamespace())) .collect(Collectors.toList()); + require(extensions.size() == 1, "Expected exactly one Base Metals client extension"); + final WorldSettingsExtension extension = extensions.get(0); + require("basemetals:configuration".equals(extension.id().toString()), "Unexpected extension id " + extension.id()); require("button.orespawn.mod.configure".equals(extension.buttonTranslationKey()), "Base Metals row does not use OreSpawn's Configure/cog action"); - final GuiScreen parent = new GuiScreen() { }; + final GuiScreen parent = new GuiScreen() { + }; final GuiScreen created = extension.createScreen(parent); + require(created instanceof BaseMetalsConfigScreen, "Extension did not create BaseMetalsConfigScreen"); + final GuiConfig screen = (GuiConfig) created; + require(screen.parentScreen == parent, "OreSpawn parent screen was not preserved"); require(screen.configElements.size() == 5, "Expected five root categories"); + final int properties = screen.configElements.stream() .mapToInt(element -> element.getChildElements().size()).sum(); + require(properties == 93, "Expected 93 Base Metals options, found " + properties); + result.setProperty("extension", extension.id().toString()); + result.setProperty("button", extension.buttonTranslationKey()); + result.setProperty("screen", created.getClass().getName()); + result.setProperty("parent", Boolean.toString(screen.parentScreen == parent)); + result.setProperty("categories", Integer.toString(screen.configElements.size())); + result.setProperty("properties", Integer.toString(properties)); + MinecraftForge.EVENT_BUS.register(this); + } + + @SubscribeEvent + public void checkModsButton(final TickEvent.ClientTickEvent event) throws IOException { + if (checkedModsButton || event.phase != TickEvent.Phase.END) { + return; + } + + // Forge creates GUI factories after mod initialization, before the first client tick. + final IModGuiFactory factory = FMLClientHandler.instance().getGuiFactoryFor( + Loader.instance().getIndexedModList().get("basemetals")); + + require(factory instanceof BaseMetalsGuiFactory, + "Forge did not load the Base Metals Mods-list GUI factory"); + require(factory.hasConfigGui(), "Forge's Config button is disabled for Base Metals"); + + final GuiModList parent = new GuiModList(new GuiMainMenu()); + final GuiScreen created = factory.createConfigGui(parent); + + require(created instanceof BaseMetalsConfigScreen, + "Mods-list Config button did not create BaseMetalsConfigScreen"); + + final GuiConfig screen = (GuiConfig) created; + + require(screen.parentScreen == parent, "Mods-list parent screen was not preserved"); + require(screen.configElements.size() == 5, "Mods-list screen lost config categories"); + Minecraft.getMinecraft().displayGuiScreen(created); + require(Minecraft.getMinecraft().currentScreen == screen, + "Mods-list config screen did not initialize for display"); + result.setProperty("modsButton", Boolean.toString(factory.hasConfigGui())); + result.setProperty("modsParent", Boolean.toString(screen.parentScreen == parent)); + result.setProperty("modsScreen", created.getClass().getName()); + final String markerPath = System.getProperty("basemetals.clientConfigProbe.marker"); + if (markerPath != null && !markerPath.trim().isEmpty()) { - final Properties result = new Properties(); - result.setProperty("extension", extension.id().toString()); - result.setProperty("button", extension.buttonTranslationKey()); - result.setProperty("screen", created.getClass().getName()); - result.setProperty("parent", Boolean.toString(screen.parentScreen == parent)); - result.setProperty("categories", Integer.toString(screen.configElements.size())); - result.setProperty("properties", Integer.toString(properties)); final File marker = new File(markerPath); final File parentDirectory = marker.getParentFile(); + if (parentDirectory != null) { parentDirectory.mkdirs(); } + try (FileOutputStream output = new FileOutputStream(marker)) { - result.store(output, "Base Metals OreSpawn client configuration probe"); + result.store(output, "Base Metals client configuration probe"); } } + + checkedModsButton = true; + + if (Boolean.getBoolean("basemetals.clientConfigProbe.exit")) { + Minecraft.getMinecraft().shutdown(); + } } private static void require(final boolean condition, final String message) { diff --git a/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsRuntimeProbe.java b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsRuntimeProbe.java index 1d351caf..7836ae52 100644 --- a/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsRuntimeProbe.java +++ b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsRuntimeProbe.java @@ -5,6 +5,8 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; import java.util.Properties; import java.util.UUID; @@ -16,6 +18,7 @@ import com.mcmoddev.basemetals.items.ItemBaseMetalsCrossbow; import com.mcmoddev.basemetals.properties.ColdIronProperty; import com.mcmoddev.basemetals.properties.StarSteelProperty; +import com.mcmoddev.basemetals.recipe.PlateRepairRecipe; import com.mcmoddev.lib.data.Names; import com.mcmoddev.lib.entity.EntityCustomArrow; import com.mcmoddev.lib.entity.EntityCustomBolt; @@ -46,9 +49,12 @@ import net.minecraft.item.crafting.CraftingManager; import net.minecraft.item.crafting.IRecipe; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.nbt.NBTTagString; import net.minecraft.potion.PotionEffect; import net.minecraft.server.MinecraftServer; import net.minecraft.server.management.PlayerInteractionManager; +import net.minecraft.stats.RecipeBookServer; import net.minecraft.tileentity.TileEntityFurnace; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; @@ -63,1278 +69,1684 @@ import net.minecraftforge.fml.common.ModContainer; import net.minecraftforge.fml.common.event.FMLServerStartedEvent; -/** Test-only packaged-runtime probe. This class never enters the public jar. */ +/** Checks gameplay and world generation in a packaged Forge server. */ @Mod( - modid = BaseMetalsRuntimeProbe.MODID, - name = "Base Metals Runtime Probe", - version = "1", - dependencies = "required-after:basemetals", - acceptedMinecraftVersions = "[1.12.2]") + modid = BaseMetalsRuntimeProbe.MODID, + name = "Base Metals Runtime Probe", + version = "1", + dependencies = "required-after:basemetals", + acceptedMinecraftVersions = "[1.12.2]") public final class BaseMetalsRuntimeProbe { - public static final String MODID = "basemetals_runtime_probe"; - - @EventHandler - public void serverStarted(final FMLServerStartedEvent event) throws IOException { - final String expectedOreSpawn = requiredProperty("basemetals.probe.expectedOrespawn"); - final boolean expectedAncientWarfare = Boolean.parseBoolean( - System.getProperty("basemetals.probe.expectedAncientWarfare", "false")); - final boolean expectedCoFHWorld = Boolean.parseBoolean( - System.getProperty("basemetals.probe.expectedCoFHWorld", "false")); - final File marker = new File(requiredProperty("basemetals.probe.marker")); - final Properties result = new Properties(); - - require(Loader.isModLoaded("basemetals"), "Base Metals did not load"); - require(Loader.isModLoaded("mmdlib"), "MMDLib did not load"); - require(Loader.isModLoaded("orespawn"), "OreSpawn did not load"); - require(Loader.isModLoaded("ancientwarfare") == expectedAncientWarfare, - "Ancient Warfare presence did not match the requested compatibility profile"); - require(Loader.isModLoaded("ancientwarfarenpc") == expectedAncientWarfare, - "Ancient Warfare NPC presence did not match the requested compatibility profile"); - require(Loader.isModLoaded("cofhworld") == expectedCoFHWorld, - "CoFH World presence did not match the requested compatibility profile"); - requireRegistered(Block.REGISTRY.getObject(new ResourceLocation("basemetals", "copper_ore")), - "basemetals:copper_ore"); - requireRegistered(Block.REGISTRY.getObject(new ResourceLocation("basemetals", "adamantine_ore")), - "basemetals:adamantine_ore"); - requireRegistered(Item.REGISTRY.getObject(new ResourceLocation("basemetals", "steel_ingot")), - "basemetals:steel_ingot"); - final int fuelFormsChecked = verifyFuelForms(); - final int fishingRodsChecked = verifyFishingRodDurability(); - final int hoeMaterialNamesChecked = verifyHoeMaterialNames(); - final int ancientWarfareHoeChecks = expectedAncientWarfare - ? verifyAncientWarfareHoes( - FMLCommonHandler.instance().getMinecraftServerInstance().getEntityWorld()) - : 0; - final int doorRecipesChecked = verifyDoorAndTrapdoorRecipes( - FMLCommonHandler.instance().getMinecraftServerInstance().getEntityWorld()); - final int railRecipesChecked = verifyRailRecipes( - FMLCommonHandler.instance().getMinecraftServerInstance().getEntityWorld()); - final int railRecipeAdvancementsChecked = verifyRailRecipeAdvancement( - FMLCommonHandler.instance().getMinecraftServerInstance()); - final int crossbowBoltsChecked = verifyCrossbowBoltImpact( - FMLCommonHandler.instance().getMinecraftServerInstance()); - final int bowArrowsChecked = verifyBowArrowImpact( - FMLCommonHandler.instance().getMinecraftServerInstance()); - final int arrowPickupIdentitiesChecked = verifyArrowPickupIdentity( - FMLCommonHandler.instance().getMinecraftServerInstance()); - final int crossbowsChecked = verifyCrossbowRegistrations(); - final int rangedItemsChecked = verifyRangedItemRegistrations(); - final int rangedDamageChecks = verifyRangedDamage( - FMLCommonHandler.instance().getMinecraftServerInstance()); - final int armorEffectChecks = verifyArmorEffects( - FMLCommonHandler.instance().getMinecraftServerInstance()); - final WorldgenCounts worldgen = expectedCoFHWorld - ? verifyCoFHWorldgen(FMLCommonHandler.instance().getMinecraftServerInstance()) - : new WorldgenCounts(0, 0); - - final String baseMetalsVersion = version("basemetals"); - final String mmdLibVersion = version("mmdlib"); - final String oreSpawnVersion = version("orespawn"); - require("2.6.0.112021".equals(baseMetalsVersion), - "Unexpected Base Metals version " + baseMetalsVersion); - // The artifact build is rc2.36, while its public FML metadata retains - // the upstream mod version rc2. - require("1.0.0-rc2".equals(mmdLibVersion), - "Unexpected MMDLib version " + mmdLibVersion); - require(expectedOreSpawn.equals(oreSpawnVersion), - "Unexpected OreSpawn version " + oreSpawnVersion + ", expected " + expectedOreSpawn); - - result.setProperty("basemetals", baseMetalsVersion); - result.setProperty("mmdlib", mmdLibVersion); - result.setProperty("orespawn", oreSpawnVersion); - result.setProperty("phase", System.getProperty("basemetals.probe.phase", "unknown")); - result.setProperty("fuelFormsChecked", Integer.toString(fuelFormsChecked)); - result.setProperty("fishingRodsChecked", Integer.toString(fishingRodsChecked)); - result.setProperty("hoeMaterialNamesChecked", Integer.toString(hoeMaterialNamesChecked)); - result.setProperty("ancientWarfare", Boolean.toString(expectedAncientWarfare)); - result.setProperty("cofhWorld", Boolean.toString(expectedCoFHWorld)); - result.setProperty("managedOres", Integer.toString(worldgen.managedOres)); - result.setProperty("cofhAntimony", Integer.toString(worldgen.cofhAntimony)); - result.setProperty("ancientWarfareHoeChecks", Integer.toString(ancientWarfareHoeChecks)); - result.setProperty("doorRecipesChecked", Integer.toString(doorRecipesChecked)); - result.setProperty("railRecipesChecked", Integer.toString(railRecipesChecked)); - result.setProperty("railRecipeAdvancementsChecked", Integer.toString(railRecipeAdvancementsChecked)); - result.setProperty("crossbowBoltsChecked", Integer.toString(crossbowBoltsChecked)); - result.setProperty("bowArrowsChecked", Integer.toString(bowArrowsChecked)); - result.setProperty("arrowPickupIdentitiesChecked", - Integer.toString(arrowPickupIdentitiesChecked)); - result.setProperty("crossbowsChecked", Integer.toString(crossbowsChecked)); - result.setProperty("rangedItemsChecked", Integer.toString(rangedItemsChecked)); - result.setProperty("rangedDamageChecks", Integer.toString(rangedDamageChecks)); - result.setProperty("armorEffectChecks", Integer.toString(armorEffectChecks)); - result.setProperty("registered", "true"); - marker.getParentFile().mkdirs(); - try (FileOutputStream output = new FileOutputStream(marker)) { - result.store(output, "Base Metals packaged-runtime qualification"); - } - FMLCommonHandler.instance().getMinecraftServerInstance().initiateShutdown(); - } - - private static WorldgenCounts verifyCoFHWorldgen(final MinecraftServer server) { - final WorldServer world = server.getWorld(0); - final BlockPos spawn = world.getSpawnPoint(); - final int centerX = spawn.getX() >> 4; - final int centerZ = spawn.getZ() >> 4; - - // Load a one-chunk border so Forge population runs for every chunk in - // the bounded 9x9 sample at the centre. - for (int chunkX = centerX - 5; chunkX <= centerX + 5; chunkX++) { - for (int chunkZ = centerZ - 5; chunkZ <= centerZ + 5; chunkZ++) { - world.getChunkProvider().provideChunk(chunkX, chunkZ); - } - } - - final Block antimony = Block.REGISTRY.getObject( - new ResourceLocation("basemetals", "antimony_ore")); - int managedOres = 0; - int cofhAntimony = 0; - for (int chunkX = centerX - 4; chunkX <= centerX + 4; chunkX++) { - for (int chunkZ = centerZ - 4; chunkZ <= centerZ + 4; chunkZ++) { - final Chunk chunk = world.getChunkProvider().provideChunk(chunkX, chunkZ); - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - for (int y = 0; y < 128; y++) { - final Block block = chunk.getBlockState( - new BlockPos(x, y, z)).getBlock(); - if (block == antimony) { - cofhAntimony++; - } else if (isManagedBaseMetalsOre(block)) { - managedOres++; - } - } - } - } - } - } - require(managedOres == 0, - "Disabled OreSpawn provider placed " + managedOres + " managed Base Metals ores"); - require(cofhAntimony > 0, - "CoFH World did not place the Base Metals antimony test ore"); - return new WorldgenCounts(managedOres, cofhAntimony); - } - - private static boolean isManagedBaseMetalsOre(final Block block) { - final ResourceLocation name = block.getRegistryName(); - if (name == null || !"basemetals".equals(name.getNamespace())) { - return false; - } - switch (name.getPath()) { - case "coldiron_ore": - case "adamantine_ore": - case "starsteel_ore": - case "copper_ore": - case "silver_ore": - case "tin_ore": - case "lead_ore": - case "zinc_ore": - case "mercury_ore": - case "nickel_ore": - case "platinum_ore": - return true; - default: - return false; - } - } - - private static final class WorldgenCounts { - private final int managedOres; - private final int cofhAntimony; - - private WorldgenCounts(final int managedOres, final int cofhAntimony) { - this.managedOres = managedOres; - this.cofhAntimony = cofhAntimony; - } - } - - private static int verifyFuelForms() { - int checked = 0; - for (final Item item : Item.REGISTRY) { - final ResourceLocation registryName = item.getRegistryName(); - if (registryName == null || !"basemetals".equals(registryName.getNamespace())) { - continue; - } - - final String path = registryName.getPath(); - if (!isNuggetOrPowder(path)) { - continue; - } - - final int expected = expectedBurnTime(path); - final int actual = TileEntityFurnace.getItemBurnTime(new ItemStack(item)); - require(actual == expected, - registryName + " has furnace burn time " + actual + ", expected " + expected); - checked++; - } - require(checked > 0, "No Base Metals nugget or powder fuel forms were checked"); - return checked; - } - - private static int verifyFishingRodDurability() { - int checked = 0; - for (final MMDMaterial material : Materials.getAllMaterials()) { - if (!material.hasItem(Names.FISHING_ROD)) { - continue; - } - - final Item fishingRod = material.getItem(Names.FISHING_ROD); - final ResourceLocation registryName = fishingRod.getRegistryName(); - if (registryName == null || !"basemetals".equals(registryName.getNamespace())) { - continue; - } - - final int expected = material.getToolDurability(); - final int actual = new ItemStack(fishingRod).getMaxDamage(); - require(actual == expected, - registryName + " has maximum durability " + actual + ", expected " + expected); - checked++; - } - require(checked == 27, - "Checked " + checked + " Base Metals fishing rods, expected 27"); - return checked; - } - - private static int verifyHoeMaterialNames() { - int checked = 0; - for (final MMDMaterial material : Materials.getAllMaterials()) { - if (!material.hasItem(Names.HOE)) { - continue; - } - - final Item hoe = material.getItem(Names.HOE); - final ResourceLocation registryName = hoe.getRegistryName(); - if (registryName == null || !"basemetals".equals(registryName.getNamespace())) { - continue; - } - - require(hoe instanceof ItemHoe, - registryName + " is not an ItemHoe"); - final String materialName = ((ItemHoe) hoe).getMaterialName(); - final ToolMaterial resolved; - try { - resolved = ToolMaterial.valueOf(materialName); - } catch (final IllegalArgumentException exception) { - throw new IllegalStateException(registryName + " exposes invalid ToolMaterial name " - + materialName, exception); - } - final ToolMaterial expected = Materials.getToolMaterialFor(material); - require(resolved == expected, - registryName + " exposes ToolMaterial " + resolved - + ", expected " + expected); - checked++; - } + public static final String MODID = "basemetals_runtime_probe"; + + @EventHandler + public void serverStarted(final FMLServerStartedEvent event) throws IOException { + final String expectedOreSpawn = requiredProperty("basemetals.probe.expectedOrespawn"); + final boolean expectedAncientWarfare = Boolean.parseBoolean( + System.getProperty("basemetals.probe.expectedAncientWarfare", "false")); + final boolean expectedCoFHWorld = Boolean.parseBoolean( + System.getProperty("basemetals.probe.expectedCoFHWorld", "false")); + final File marker = new File(requiredProperty("basemetals.probe.marker")); + final Properties result = new Properties(); + + require(Loader.isModLoaded("basemetals"), "Base Metals did not load"); + require(Loader.isModLoaded("mmdlib"), "MMDLib did not load"); + require(Loader.isModLoaded("orespawn"), "OreSpawn did not load"); + require(Loader.isModLoaded("ancientwarfare") == expectedAncientWarfare, + "Ancient Warfare presence did not match the requested compatibility profile"); + require(Loader.isModLoaded("ancientwarfarenpc") == expectedAncientWarfare, + "Ancient Warfare NPC presence did not match the requested compatibility profile"); + require(Loader.isModLoaded("cofhworld") == expectedCoFHWorld, + "CoFH World presence did not match the requested compatibility profile"); + requireRegistered(Block.REGISTRY.getObject(new ResourceLocation("basemetals", "copper_ore")), + "basemetals:copper_ore"); + requireRegistered(Block.REGISTRY.getObject(new ResourceLocation("basemetals", "adamantine_ore")), + "basemetals:adamantine_ore"); + requireRegistered(Item.REGISTRY.getObject(new ResourceLocation("basemetals", "steel_ingot")), + "basemetals:steel_ingot"); + + final int fuelFormsChecked = verifyFuelForms(); + final int fishingRodsChecked = verifyFishingRodDurability(); + final int hoeMaterialNamesChecked = verifyHoeMaterialNames(); + final int ancientWarfareHoeChecks = expectedAncientWarfare + ? verifyAncientWarfareHoes( + FMLCommonHandler.instance().getMinecraftServerInstance().getEntityWorld()) + : 0; + final int doorRecipesChecked = verifyDoorAndTrapdoorRecipes( + FMLCommonHandler.instance().getMinecraftServerInstance().getEntityWorld()); + final int railRecipesChecked = verifyRailRecipes( + FMLCommonHandler.instance().getMinecraftServerInstance().getEntityWorld()); + final boolean expectPlateRepairs = Boolean.parseBoolean(System.getProperty( + "basemetals.probe.expectPlateRepairs", "true")); + final int plateRepairChecks = expectPlateRepairs + ? verifyPlateRepairRecipes(FMLCommonHandler.instance().getMinecraftServerInstance()) + : verifyPlateRepairsDisabled(); + final int railRecipeAdvancementsChecked = verifyRailRecipeAdvancement( + FMLCommonHandler.instance().getMinecraftServerInstance()); + final int materialRecipeAdvancementsChecked = verifyMaterialRecipeAdvancements( + FMLCommonHandler.instance().getMinecraftServerInstance()); + final int crossbowBoltsChecked = verifyCrossbowBoltImpact( + FMLCommonHandler.instance().getMinecraftServerInstance()); + final int bowArrowsChecked = verifyBowArrowImpact( + FMLCommonHandler.instance().getMinecraftServerInstance()); + final int arrowPickupIdentitiesChecked = verifyArrowPickupIdentity( + FMLCommonHandler.instance().getMinecraftServerInstance()); + final int crossbowsChecked = verifyCrossbowRegistrations(); + final int rangedItemsChecked = verifyRangedItemRegistrations(); + final int rangedDamageChecks = verifyRangedDamage( + FMLCommonHandler.instance().getMinecraftServerInstance()); + final int armorEffectChecks = verifyArmorEffects( + FMLCommonHandler.instance().getMinecraftServerInstance()); + final WorldgenCounts worldgen = expectedCoFHWorld + ? verifyCoFHWorldgen(FMLCommonHandler.instance().getMinecraftServerInstance()) + : new WorldgenCounts(0, 0); + + final String baseMetalsVersion = version("basemetals"); + final String mmdLibVersion = version("mmdlib"); + final String oreSpawnVersion = version("orespawn"); + + require("2.6.0.112021".equals(baseMetalsVersion), + "Unexpected Base Metals version " + baseMetalsVersion); + // MMDLib rc2.36 still reports "rc2" in its mod metadata. + require("1.0.0-rc2".equals(mmdLibVersion), + "Unexpected MMDLib version " + mmdLibVersion); + require(expectedOreSpawn.equals(oreSpawnVersion), + "Unexpected OreSpawn version " + oreSpawnVersion + ", expected " + expectedOreSpawn); + + result.setProperty("basemetals", baseMetalsVersion); + result.setProperty("mmdlib", mmdLibVersion); + result.setProperty("orespawn", oreSpawnVersion); + result.setProperty("phase", System.getProperty("basemetals.probe.phase", "unknown")); + result.setProperty("fuelFormsChecked", Integer.toString(fuelFormsChecked)); + result.setProperty("fishingRodsChecked", Integer.toString(fishingRodsChecked)); + result.setProperty("hoeMaterialNamesChecked", Integer.toString(hoeMaterialNamesChecked)); + result.setProperty("ancientWarfare", Boolean.toString(expectedAncientWarfare)); + result.setProperty("cofhWorld", Boolean.toString(expectedCoFHWorld)); + result.setProperty("managedOres", Integer.toString(worldgen.managedOres)); + result.setProperty("cofhAntimony", Integer.toString(worldgen.cofhAntimony)); + result.setProperty("ancientWarfareHoeChecks", Integer.toString(ancientWarfareHoeChecks)); + result.setProperty("doorRecipesChecked", Integer.toString(doorRecipesChecked)); + result.setProperty("railRecipesChecked", Integer.toString(railRecipesChecked)); + result.setProperty("plateRepairChecks", Integer.toString(plateRepairChecks)); + result.setProperty("railRecipeAdvancementsChecked", Integer.toString(railRecipeAdvancementsChecked)); + result.setProperty("materialRecipeAdvancementsChecked", + Integer.toString(materialRecipeAdvancementsChecked)); + result.setProperty("crossbowBoltsChecked", Integer.toString(crossbowBoltsChecked)); + result.setProperty("bowArrowsChecked", Integer.toString(bowArrowsChecked)); + result.setProperty("arrowPickupIdentitiesChecked", + Integer.toString(arrowPickupIdentitiesChecked)); + result.setProperty("crossbowsChecked", Integer.toString(crossbowsChecked)); + result.setProperty("rangedItemsChecked", Integer.toString(rangedItemsChecked)); + result.setProperty("rangedDamageChecks", Integer.toString(rangedDamageChecks)); + result.setProperty("armorEffectChecks", Integer.toString(armorEffectChecks)); + result.setProperty("registered", "true"); + marker.getParentFile().mkdirs(); + + try (FileOutputStream output = new FileOutputStream(marker)) { + result.store(output, "Base Metals packaged-runtime qualification"); + } + + FMLCommonHandler.instance().getMinecraftServerInstance().initiateShutdown(); + } + + private static WorldgenCounts verifyCoFHWorldgen(final MinecraftServer server) { + final WorldServer world = server.getWorld(0); + final BlockPos spawn = world.getSpawnPoint(); + final int centerX = spawn.getX() >> 4; + final int centerZ = spawn.getZ() >> 4; + + // Load a border so Forge finishes populating the central 9x9 sample. + for (int chunkX = centerX - 5; chunkX <= centerX + 5; chunkX++) { + for (int chunkZ = centerZ - 5; chunkZ <= centerZ + 5; chunkZ++) { + world.getChunkProvider().provideChunk(chunkX, chunkZ); + } + } + + final Block antimony = Block.REGISTRY.getObject( + new ResourceLocation("basemetals", "antimony_ore")); + int managedOres = 0; + int cofhAntimony = 0; + + for (int chunkX = centerX - 4; chunkX <= centerX + 4; chunkX++) { + for (int chunkZ = centerZ - 4; chunkZ <= centerZ + 4; chunkZ++) { + final Chunk chunk = world.getChunkProvider().provideChunk(chunkX, chunkZ); + + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + for (int y = 0; y < 128; y++) { + final Block block = chunk.getBlockState( + new BlockPos(x, y, z)).getBlock(); + + if (block == antimony) { + cofhAntimony++; + } else if (isManagedBaseMetalsOre(block)) { + managedOres++; + } + } + } + } + } + } + + require(managedOres == 0, + "Disabled OreSpawn provider placed " + managedOres + " managed Base Metals ores"); + require(cofhAntimony > 0, + "CoFH World did not place the Base Metals antimony test ore"); + + return new WorldgenCounts(managedOres, cofhAntimony); + } + + private static boolean isManagedBaseMetalsOre(final Block block) { + final ResourceLocation name = block.getRegistryName(); + + if (name == null || !"basemetals".equals(name.getNamespace())) { + return false; + } + + switch (name.getPath()) { + case "coldiron_ore" : + case "adamantine_ore" : + case "starsteel_ore" : + case "copper_ore" : + case "silver_ore" : + case "tin_ore" : + case "lead_ore" : + case "zinc_ore" : + case "mercury_ore" : + case "nickel_ore" : + case "platinum_ore" : + return true; + default : + return false; + } + } + + private static final class WorldgenCounts { + private final int managedOres; + private final int cofhAntimony; + + private WorldgenCounts(final int managedOres, final int cofhAntimony) { + this.managedOres = managedOres; + this.cofhAntimony = cofhAntimony; + } + } + + private static int verifyFuelForms() { + int checked = 0; + + for (final Item item : Item.REGISTRY) { + final ResourceLocation registryName = item.getRegistryName(); + + if (registryName == null || !"basemetals".equals(registryName.getNamespace())) { + continue; + } + + final String path = registryName.getPath(); + + if (!isNuggetOrPowder(path)) { + continue; + } + + final int expected = expectedBurnTime(path); + final int actual = TileEntityFurnace.getItemBurnTime(new ItemStack(item)); + + require(actual == expected, + registryName + " has furnace burn time " + actual + ", expected " + expected); + checked++; + } + + require(checked > 0, "No Base Metals nugget or powder fuel forms were checked"); + + return checked; + } + + private static int verifyFishingRodDurability() { + int checked = 0; + + for (final MMDMaterial material : Materials.getAllMaterials()) { + if (!material.hasItem(Names.FISHING_ROD)) { + continue; + } + + final Item fishingRod = material.getItem(Names.FISHING_ROD); + final ResourceLocation registryName = fishingRod.getRegistryName(); + + if (registryName == null || !"basemetals".equals(registryName.getNamespace())) { + continue; + } + + final int expected = material.getToolDurability(); + final int actual = new ItemStack(fishingRod).getMaxDamage(); + + require(actual == expected, + registryName + " has maximum durability " + actual + ", expected " + expected); + checked++; + } + + require(checked == 27, + "Checked " + checked + " Base Metals fishing rods, expected 27"); + + return checked; + } + + private static int verifyHoeMaterialNames() { + int checked = 0; + + for (final MMDMaterial material : Materials.getAllMaterials()) { + if (!material.hasItem(Names.HOE)) { + continue; + } + + final Item hoe = material.getItem(Names.HOE); + final ResourceLocation registryName = hoe.getRegistryName(); + + if (registryName == null || !"basemetals".equals(registryName.getNamespace())) { + continue; + } + + require(hoe instanceof ItemHoe, + registryName + " is not an ItemHoe"); + + final String materialName = ((ItemHoe) hoe).getMaterialName(); + final ToolMaterial resolved; + + try { + resolved = ToolMaterial.valueOf(materialName); + } catch (final IllegalArgumentException exception) { + throw new IllegalStateException(registryName + " exposes invalid ToolMaterial name " + + materialName, exception); + } + + final ToolMaterial expected = Materials.getToolMaterialFor(material); + + require(resolved == expected, + registryName + " exposes ToolMaterial " + resolved + + ", expected " + expected); + checked++; + } + require(checked == 24, "Checked " + checked + " Base Metals hoe material names, expected 24"); - return checked; - } - - private static int verifyAncientWarfareHoes(final World world) { - try { - final Class workerClass = Class.forName( - "net.shadowmage.ancientwarfare.npc.entity.NpcWorker"); - final Class workTypeClass = Class.forName( - "net.shadowmage.ancientwarfare.core.interfaces.IWorkSite$WorkType"); - final Object farming = enumConstant(workTypeClass, "FARMING"); - final Method effectivenessMethod = workerClass.getMethod( - "getWorkEffectiveness", workTypeClass); - int checked = 0; - for (final String path : new String[] { - "emerald_hoe", "steel_hoe", "adamantine_hoe" }) { - final EntityLivingBase worker = (EntityLivingBase) workerClass - .getConstructor(World.class).newInstance(world); - worker.setHeldItem(EnumHand.MAIN_HAND, - new ItemStack(requireItem("basemetals", path))); - final float effectiveness = ((Number) effectivenessMethod - .invoke(worker, farming)).floatValue(); - require(!Float.isNaN(effectiveness) && !Float.isInfinite(effectiveness) - && effectiveness > 0.0F, - "Ancient Warfare returned invalid work effectiveness " - + effectiveness + " for basemetals:" + path); - checked++; - } - require(checked == 3, - "Checked " + checked + " Ancient Warfare hoes, expected 3"); - return checked; - } catch (final InvocationTargetException exception) { - throw new IllegalStateException("Ancient Warfare rejected a Base Metals hoe", - exception.getCause()); - } catch (final ReflectiveOperationException exception) { - throw new IllegalStateException( - "Could not exercise Ancient Warfare's farming effectiveness path", exception); - } - } - - private static Object enumConstant(final Class enumClass, final String name) { - for (final Object constant : enumClass.getEnumConstants()) { - if (((Enum) constant).name().equals(name)) { - return constant; - } - } - throw new IllegalStateException("Missing enum constant " + enumClass.getName() + "." + name); - } - - private static boolean isNuggetOrPowder(final String path) { - return path.endsWith("_nugget") - || path.endsWith("_powder") - || path.endsWith("_smallpowder"); - } - - private static int expectedBurnTime(final String path) { - if (path.startsWith("coal_") || path.startsWith("charcoal_")) { - return path.endsWith("_powder") ? 1600 : 200; - } - return 0; - } - - private static int verifyDoorAndTrapdoorRecipes(final World world) { - int checked = 0; - checked += verifyDoorAndTrapdoorRecipe(world, net.minecraft.init.Items.DIAMOND, "diamond"); - checked += verifyDoorAndTrapdoorRecipe(world, net.minecraft.init.Items.EMERALD, "emerald"); - checked += verifyDoorAndTrapdoorRecipe(world, net.minecraft.init.Items.GOLD_INGOT, "gold"); - checked += verifyDoorAndTrapdoorRecipe(world, net.minecraft.init.Items.QUARTZ, "quartz"); - return checked; - } - - private static int verifyRailRecipes(final World world) { - final Item steel = requireItem("basemetals", "steel_ingot"); - final Item stick = net.minecraft.init.Items.STICK; - final Item redstone = net.minecraft.init.Items.REDSTONE; - final Item redstoneTorch = Item.getItemFromBlock(Blocks.REDSTONE_TORCH); - final Item stonePressurePlate = Item.getItemFromBlock(Blocks.STONE_PRESSURE_PLATE); - - verifyRailRecipe(world, "rail", Item.getItemFromBlock(Blocks.RAIL), 16, - steel, null, steel, - steel, stick, steel, - steel, null, steel); - verifyRailRecipe(world, "activator_rail", Item.getItemFromBlock(Blocks.ACTIVATOR_RAIL), 6, - steel, stick, steel, - steel, redstoneTorch, steel, - steel, stick, steel); - verifyRailRecipe(world, "detector_rail", Item.getItemFromBlock(Blocks.DETECTOR_RAIL), 6, - steel, null, steel, - steel, stonePressurePlate, steel, - steel, redstone, steel); - return 3; - } - - private static int verifyRailRecipeAdvancement(final MinecraftServer server) { - final ResourceLocation advancementId = new ResourceLocation( - "basemetals", "recipes/transportation/rail"); - final Advancement advancement = server.getAdvancementManager().getAdvancement(advancementId); - require(advancement != null, "Recipe-book advancement was not loaded: " + advancementId); - require(advancement.getCriteria().containsKey("has_iron_ingot"), - advancementId + " does not recognize iron ingots"); - require(advancement.getCriteria().containsKey("has_steel_ingot"), - advancementId + " does not recognize Base Metals steel ingots"); - require(advancement.getCriteria().containsKey("has_the_recipe"), - advancementId + " lacks its recipe-unlocked criterion"); - require(advancement.getRequirements().length == 1 - && advancement.getRequirements()[0].length == 3, - advancementId + " discovery criteria are not alternatives"); - return 1; - } - - private static int verifyCrossbowBoltImpact(final MinecraftServer server) { - final WorldServer world = server.getWorld(0); - final Item crossbow = requireItem("basemetals", "steel_crossbow"); - final Item boltItem = requireItem("basemetals", "steel_bolt"); - final ItemStack crossbowStack = new ItemStack(crossbow); - final ItemStack ammunition = new ItemStack(boltItem); - final EntityPlayerMP shooter = new EntityPlayerMP(server, world, - new GameProfile(UUID.randomUUID(), "BaseMetalsBoltProbe"), - new PlayerInteractionManager(world)); - final BlockPos spawn = world.getSpawnPoint(); - final double x = spawn.getX() + 0.5D; - final double y = spawn.getY() + 16.0D; - final double z = spawn.getZ() + 0.5D; - shooter.setPositionAndRotation(x, y, z, 0.0F, 0.0F); - shooter.setHeldItem(EnumHand.OFF_HAND, ammunition); - - final EntityIronGolem target = new EntityIronGolem(world); - target.setPosition(x, y, z + 2.5D); - require(world.spawnEntity(target), "Could not spawn the crossbow impact target"); - final float healthBefore = target.getHealth(); - final int boltsBefore = countBolts(world); - EntityCustomBolt projectile = null; - try { - crossbow.onPlayerStoppedUsing(crossbowStack, world, shooter, - crossbow.getMaxItemUseDuration(crossbowStack) - 20); - require(countBolts(world) == boltsBefore + 1, - "Base Metals crossbow did not create a server-side bolt"); - projectile = findLiveBolt(world); - require(projectile != null, "Spawned Base Metals bolt could not be located"); - final MMDMaterial steel = Materials.getMaterialByName(MaterialNames.STEEL); - requireDamage(steel.getBaseAttackDamage() * 2.0D, projectile.getDamage(), - "steel crossbow and bolt impact projectile"); - final ItemStack savedAmmunition = EntityHelpers.readFromNBTItemStack( - projectile.writeToNBT(new NBTTagCompound())); - require(savedAmmunition.getItem() == boltItem && savedAmmunition.getCount() == 1, - "Base Metals bolt did not preserve its ammunition item"); - for (int tick = 0; tick < 4 && target.getHealth() == healthBefore; tick++) { - projectile.onUpdate(); - } - require(target.getHealth() < healthBefore, - "Base Metals crossbow bolt did not damage its target"); - require(ammunition.isEmpty(), - "Base Metals crossbow consumed an unexpected number of bolts"); - require(crossbowStack.getItemDamage() == 1, - "Base Metals crossbow did not lose one durability after firing"); - } finally { - if (projectile != null) { - projectile.setDead(); - } - target.setDead(); - } - return 1; - } - - private static int verifyBowArrowImpact(final MinecraftServer server) { - final WorldServer world = server.getWorld(0); - final Item bow = requireItem("basemetals", "steel_bow"); - final Item arrowItem = requireItem("basemetals", "steel_arrow"); - final ItemStack bowStack = new ItemStack(bow); - final ItemStack ammunition = new ItemStack(arrowItem); - final EntityPlayerMP shooter = new EntityPlayerMP(server, world, - new GameProfile(UUID.randomUUID(), "BaseMetalsArrowProbe"), - new PlayerInteractionManager(world)); - final BlockPos spawn = world.getSpawnPoint(); - final double x = spawn.getX() + 0.5D; - final double y = spawn.getY() + 16.0D; - final double z = spawn.getZ() + 0.5D; - shooter.setPositionAndRotation(x, y, z, 0.0F, 0.0F); - shooter.setHeldItem(EnumHand.OFF_HAND, ammunition); - - final EntityIronGolem target = new EntityIronGolem(world); - target.setPosition(x, y, z + 2.5D); - require(world.spawnEntity(target), "Could not spawn the bow impact target"); - final float healthBefore = target.getHealth(); - final int arrowsBefore = countArrows(world); - EntityArrow projectile = null; - try { - bow.onPlayerStoppedUsing(bowStack, world, shooter, - bow.getMaxItemUseDuration(bowStack) - 20); - require(countArrows(world) == arrowsBefore + 1, - "Base Metals bow did not create a server-side arrow"); - projectile = findLiveArrow(world); - require(projectile != null, "Spawned Base Metals arrow could not be located"); - final MMDMaterial steel = Materials.getMaterialByName(MaterialNames.STEEL); - requireDamage(steel.getBaseAttackDamage() * 2.0D, projectile.getDamage(), - "steel bow and arrow impact projectile"); - final ItemStack savedAmmunition = EntityHelpers.readFromNBTItemStack( - projectile.writeToNBT(new NBTTagCompound())); - require(savedAmmunition.getItem() == arrowItem && savedAmmunition.getCount() == 1, - "Base Metals arrow did not preserve its ammunition item"); - for (int tick = 0; tick < 4 && target.getHealth() == healthBefore; tick++) { - projectile.onUpdate(); - } - require(target.getHealth() < healthBefore, - "Base Metals bow arrow did not damage its target"); - require(ammunition.isEmpty(), - "Base Metals bow consumed an unexpected number of arrows"); - require(bowStack.getItemDamage() == 1, - "Base Metals bow did not lose one durability after firing"); - } finally { - if (projectile != null) { - projectile.setDead(); - } - target.setDead(); - } - return 1; - } - - private static int verifyArrowPickupIdentity(final MinecraftServer server) { - final WorldServer world = server.getWorld(0); - final EntityPlayerMP shooter = new EntityPlayerMP(server, world, - new GameProfile(UUID.randomUUID(), "BaseMetalsArrowIdentityProbe"), - new PlayerInteractionManager(world)); - final BlockPos spawn = world.getSpawnPoint(); - shooter.setPositionAndRotation(spawn.getX() + 0.5D, spawn.getY() + 16.0D, - spawn.getZ() + 0.5D, 0.0F, 0.0F); - - int checked = 0; - for (final MMDMaterial material : Materials.getAllMaterials()) { - if (!isBaseMetalsItem(material, Names.ARROW)) { - continue; - } - final Item arrowItem = material.getItem(Names.ARROW); - final ItemStack inventoryAmmunition = new ItemStack(arrowItem); - final EntityCustomArrow projectile = ((ItemBaseMetalsArrow) arrowItem) - .createArrow(world, inventoryAmmunition, shooter); - inventoryAmmunition.shrink(1); - require(inventoryAmmunition.isEmpty(), - arrowItem.getRegistryName() + " identity test did not consume its source stack"); - - final NBTTagCompound saved = projectile.writeToNBT(new NBTTagCompound()); - final ItemStack pickup = EntityHelpers.readFromNBTItemStack(saved); - require(pickup.getItem() == arrowItem && pickup.getCount() == 1, - arrowItem.getRegistryName() + " became another item before pickup"); - - final EntityCustomArrow reloaded = new EntityCustomArrow(world); - reloaded.readFromNBT(saved); - final ItemStack reloadedPickup = EntityHelpers.readFromNBTItemStack( - reloaded.writeToNBT(new NBTTagCompound())); - require(reloadedPickup.getItem() == arrowItem && reloadedPickup.getCount() == 1, - arrowItem.getRegistryName() + " lost its identity after save and reload"); - projectile.setDead(); - reloaded.setDead(); - checked++; - } - require(checked == 27, - "Checked " + checked + " Base Metals arrow identities, expected 27"); - - final Item arrowItem = requireItem("basemetals", "steel_arrow"); - final ItemStack ammunition = new ItemStack(arrowItem); - final ItemStack vanillaBow = new ItemStack(net.minecraft.init.Items.BOW); - shooter.setHeldItem(EnumHand.OFF_HAND, ammunition); - final int arrowsBefore = countArrows(world); - EntityArrow projectile = null; - try { - net.minecraft.init.Items.BOW.onPlayerStoppedUsing(vanillaBow, world, shooter, - vanillaBow.getMaxItemUseDuration() - 20); - require(countArrows(world) == arrowsBefore + 1, - "Vanilla bow did not create a Base Metals arrow projectile"); - projectile = findLiveArrow(world); - require(projectile instanceof EntityCustomArrow, - "Vanilla bow did not retain the Base Metals arrow entity"); - require(ammunition.isEmpty(), - "Vanilla bow did not consume the last Base Metals arrow"); - final ItemStack pickup = EntityHelpers.readFromNBTItemStack( - projectile.writeToNBT(new NBTTagCompound())); - require(pickup.getItem() == arrowItem && pickup.getCount() == 1, - "Vanilla bow changed a Base Metals arrow into another pickup item"); - } finally { - if (projectile != null) { - projectile.setDead(); - } - } - return checked + 1; - } - - private static int verifyCrossbowRegistrations() { - int checked = 0; - for (final MMDMaterial material : Materials.getAllMaterials()) { - if (!material.hasItem(Names.CROSSBOW)) { - continue; - } - final Item crossbow = material.getItem(Names.CROSSBOW); - final ResourceLocation registryName = crossbow.getRegistryName(); - if (registryName == null || !"basemetals".equals(registryName.getNamespace())) { - continue; - } - require(crossbow instanceof ItemBaseMetalsCrossbow, - registryName + " does not use the corrected Base Metals crossbow implementation"); - checked++; - } - require(checked == 27, "Checked " + checked + " Base Metals crossbows, expected 27"); - return checked; - } - - private static int verifyRangedItemRegistrations() { - int arrows = 0; - int bolts = 0; - int bows = 0; - for (final MMDMaterial material : Materials.getAllMaterials()) { - if (isBaseMetalsItem(material, Names.ARROW)) { - require(material.getItem(Names.ARROW) instanceof ItemBaseMetalsArrow, - material.getItem(Names.ARROW).getRegistryName() - + " does not use the material-damage arrow implementation"); - arrows++; - } - if (isBaseMetalsItem(material, Names.BOLT)) { - require(material.getItem(Names.BOLT) instanceof ItemBaseMetalsBolt, - material.getItem(Names.BOLT).getRegistryName() - + " does not use the material-damage bolt implementation"); - bolts++; - } - if (isBaseMetalsItem(material, Names.BOW)) { - require(material.getItem(Names.BOW) instanceof ItemBaseMetalsBow, - material.getItem(Names.BOW).getRegistryName() - + " does not use the material-damage bow implementation"); - bows++; - } - } - require(arrows == 27, "Checked " + arrows + " Base Metals arrows, expected 27"); - require(bolts == 27, "Checked " + bolts + " Base Metals bolts, expected 27"); - require(bows == 27, "Checked " + bows + " Base Metals bows, expected 27"); - return arrows + bolts + bows; - } - - private static boolean isBaseMetalsItem(final MMDMaterial material, final Names name) { - if (!material.hasItem(name)) { - return false; - } - final ResourceLocation registryName = material.getItem(name).getRegistryName(); - return registryName != null && "basemetals".equals(registryName.getNamespace()); - } - - private static int verifyRangedDamage(final MinecraftServer server) { - final WorldServer world = server.getWorld(0); - final EntityPlayerMP shooter = new EntityPlayerMP(server, world, - new GameProfile(UUID.randomUUID(), "BaseMetalsDamageProbe"), - new PlayerInteractionManager(world)); - final BlockPos spawn = world.getSpawnPoint(); - shooter.setPositionAndRotation(spawn.getX() + 0.5D, spawn.getY() + 16.0D, - spawn.getZ() + 0.5D, 0.0F, 0.0F); - int checked = 0; - - for (final MMDMaterial material : Materials.getAllMaterials()) { - if (!isBaseMetalsItem(material, Names.ARROW) - || !isBaseMetalsItem(material, Names.BOLT) - || !isBaseMetalsItem(material, Names.BOW) - || !isBaseMetalsItem(material, Names.CROSSBOW)) { - continue; - } - final double component = material.getBaseAttackDamage(); - requireDamage(1.0D + component, createArrowDamage(world, shooter, material), - material.getName() + " arrow ammunition"); - requireDamage(1.0D + component, createBoltDamage(world, shooter, material), - material.getName() + " bolt ammunition"); - requireDamage(component + component, - fireBowDamage(world, shooter, material.getItem(Names.BOW), - material.getItem(Names.ARROW), 0), - material.getName() + " matching bow and arrow"); - requireDamage(component + component, - fireCrossbowDamage(world, shooter, material.getItem(Names.CROSSBOW), - material.getItem(Names.BOLT), 0), - material.getName() + " matching crossbow and bolt"); - checked += 4; - } - require(checked == 108, "Checked " + checked + " ranged material combinations, expected 108"); - - final MMDMaterial gold = Materials.getMaterialByName(MaterialNames.GOLD); - final MMDMaterial iron = Materials.getMaterialByName(MaterialNames.IRON); - final MMDMaterial adamantine = Materials.getMaterialByName(MaterialNames.ADAMANTINE); - final MMDMaterial steel = Materials.getMaterialByName(MaterialNames.STEEL); - require(createArrowDamage(world, shooter, gold) - < createArrowDamage(world, shooter, iron) - && createArrowDamage(world, shooter, iron) - < createArrowDamage(world, shooter, adamantine), - "Gold, iron, and Adamantine arrows do not have increasing material damage"); - require(createBoltDamage(world, shooter, gold) - < createBoltDamage(world, shooter, iron) - && createBoltDamage(world, shooter, iron) - < createBoltDamage(world, shooter, adamantine), - "Gold, iron, and Adamantine bolts do not have increasing material damage"); - - requireDamage(2.0D, - fireBowDamage(world, shooter, net.minecraft.init.Items.BOW, - net.minecraft.init.Items.ARROW, 0), - "vanilla bow and arrow"); - checked++; - requireDamage(1.0D + adamantine.getBaseAttackDamage(), - fireBowDamage(world, shooter, net.minecraft.init.Items.BOW, - adamantine.getItem(Names.ARROW), 0), - "vanilla bow and Adamantine arrow"); - checked++; - requireDamage(1.0D + adamantine.getBaseAttackDamage(), - fireBowDamage(world, shooter, adamantine.getItem(Names.BOW), - net.minecraft.init.Items.ARROW, 0), - "Adamantine bow and vanilla arrow"); - checked++; - - final double goldBowAdamantineArrow = fireBowDamage(world, shooter, - gold.getItem(Names.BOW), adamantine.getItem(Names.ARROW), 0); - final double adamantineBowGoldArrow = fireBowDamage(world, shooter, - adamantine.getItem(Names.BOW), gold.getItem(Names.ARROW), 0); - requireDamage(gold.getBaseAttackDamage() + adamantine.getBaseAttackDamage(), - goldBowAdamantineArrow, "gold bow and Adamantine arrow"); - requireDamage(goldBowAdamantineArrow, adamantineBowGoldArrow, - "swapped bow and arrow materials"); - checked += 2; - - final double goldCrossbowAdamantineBolt = fireCrossbowDamage(world, shooter, - gold.getItem(Names.CROSSBOW), adamantine.getItem(Names.BOLT), 0); - final double adamantineCrossbowGoldBolt = fireCrossbowDamage(world, shooter, - adamantine.getItem(Names.CROSSBOW), gold.getItem(Names.BOLT), 0); - requireDamage(gold.getBaseAttackDamage() + adamantine.getBaseAttackDamage(), - goldCrossbowAdamantineBolt, "gold crossbow and Adamantine bolt"); - requireDamage(goldCrossbowAdamantineBolt, adamantineCrossbowGoldBolt, - "swapped crossbow and bolt materials"); - checked += 2; - - final int powerLevel = 2; - final double powerBonus = powerLevel * 0.5D + 0.5D; - requireDamage(steel.getBaseAttackDamage() * 2.0D + powerBonus, - fireBowDamage(world, shooter, steel.getItem(Names.BOW), - steel.getItem(Names.ARROW), powerLevel), - "Power-enchanted steel bow and arrow"); - requireDamage(steel.getBaseAttackDamage() * 2.0D + powerBonus, - fireCrossbowDamage(world, shooter, steel.getItem(Names.CROSSBOW), - steel.getItem(Names.BOLT), powerLevel), - "Power-enchanted steel crossbow and bolt"); - checked += 2; - - final ItemBolt neutralBolt = new ItemBolt(); - requireDamage(1.0D + adamantine.getBaseAttackDamage(), - fireCrossbowDamage(world, shooter, adamantine.getItem(Names.CROSSBOW), - neutralBolt, 0), - "Adamantine crossbow and neutral third-party bolt"); - checked++; - - final ItemArrow thirdPartyArrow = new ItemArrow() { - @Override - public EntityArrow createArrow(final World arrowWorld, final ItemStack stack, - final net.minecraft.entity.EntityLivingBase arrowShooter) { - final EntityArrow projectile = super.createArrow(arrowWorld, stack, arrowShooter); - projectile.setDamage(4.25D); - return projectile; - } - }; - requireDamage(4.25D - 1.0D + adamantine.getBaseAttackDamage(), - fireBowDamage(world, shooter, adamantine.getItem(Names.BOW), - thirdPartyArrow, 0), - "Adamantine bow and third-party arrow"); - checked++; - require(checked == 119, "Checked " + checked + " ranged damage cases, expected 119"); - return checked; - } - - private static double fireBowDamage(final World world, final EntityPlayer shooter, - final Item bow, final Item arrow, final int powerLevel) { - final ItemStack bowStack = new ItemStack(bow); - if (powerLevel > 0) { - bowStack.addEnchantment(Enchantments.POWER, powerLevel); - } - final ItemStack ammunition = new ItemStack(arrow, 2); - shooter.setHeldItem(EnumHand.OFF_HAND, ammunition); - final int before = countArrows(world); - EntityArrow projectile = null; - try { - bow.onPlayerStoppedUsing(bowStack, world, shooter, - bow.getMaxItemUseDuration(bowStack) - 20); - require(countArrows(world) == before + 1, - bow.getRegistryName() + " did not create a server-side arrow"); - projectile = findLiveArrow(world); - require(projectile != null, "Spawned arrow could not be located"); - require(ammunition.getCount() == 1, - bow.getRegistryName() + " consumed an unexpected number of arrows"); - require(bowStack.getItemDamage() == 1, - bow.getRegistryName() + " did not lose one durability after firing"); - return projectile.getDamage(); - } finally { - if (projectile != null) { - projectile.setDead(); - } - shooter.setHeldItem(EnumHand.OFF_HAND, ItemStack.EMPTY); - } - } - - private static double fireCrossbowDamage(final World world, final EntityPlayer shooter, - final Item crossbow, final Item bolt, final int powerLevel) { - final ItemStack crossbowStack = new ItemStack(crossbow); - if (powerLevel > 0) { - crossbowStack.addEnchantment(Enchantments.POWER, powerLevel); - } - final ItemStack ammunition = new ItemStack(bolt, 2); - shooter.setHeldItem(EnumHand.OFF_HAND, ammunition); - final int before = countBolts(world); - EntityCustomBolt projectile = null; - try { - crossbow.onPlayerStoppedUsing(crossbowStack, world, shooter, - crossbow.getMaxItemUseDuration(crossbowStack) - 20); - require(countBolts(world) == before + 1, - crossbow.getRegistryName() + " did not create a server-side bolt"); - projectile = findLiveBolt(world); - require(projectile != null, "Spawned bolt could not be located"); - require(ammunition.getCount() == 1, - crossbow.getRegistryName() + " consumed an unexpected number of bolts"); - require(crossbowStack.getItemDamage() == 1, - crossbow.getRegistryName() + " did not lose one durability after firing"); - return projectile.getDamage(); - } finally { - if (projectile != null) { - projectile.setDead(); - } - shooter.setHeldItem(EnumHand.OFF_HAND, ItemStack.EMPTY); - } - } - - private static int countArrows(final World world) { - int count = 0; - for (final Entity entity : world.loadedEntityList) { - if (entity instanceof EntityArrow && !(entity instanceof EntityCustomBolt) - && !entity.isDead) { - count++; - } - } - return count; - } - - private static EntityArrow findLiveArrow(final World world) { - for (final Entity entity : world.loadedEntityList) { - if (entity instanceof EntityArrow && !(entity instanceof EntityCustomBolt) - && !entity.isDead) { - return (EntityArrow) entity; - } - } - return null; - } - - private static void requireDamage(final double expected, final double actual, - final String description) { - require(Math.abs(expected - actual) < 0.000001D, - description + " has projectile base damage " + actual + ", expected " + expected); - } - - private static double createArrowDamage(final World world, final EntityPlayer shooter, - final MMDMaterial material) { - final Item item = material.getItem(Names.ARROW); - require(item instanceof ItemArrow, - material.getName() + " arrow is not an ItemArrow"); - final EntityArrow projectile = ((ItemArrow) item).createArrow( - world, new ItemStack(item), shooter); - final double damage = projectile.getDamage(); - projectile.setDead(); - return damage; - } - - private static double createBoltDamage(final World world, final EntityPlayer shooter, - final MMDMaterial material) { - final Item item = material.getItem(Names.BOLT); - require(item instanceof ItemBolt, - material.getName() + " bolt is not an ItemBolt"); - final EntityCustomBolt projectile = ((ItemBolt) item).createBolt( - world, new ItemStack(item), shooter); - final double damage = projectile.getDamage(); - projectile.setDead(); - return damage; - } - - private static int countBolts(final World world) { - int count = 0; - for (final Entity entity : world.loadedEntityList) { - if (entity instanceof EntityCustomBolt && !entity.isDead) { - count++; - } - } - return count; - } - - private static EntityCustomBolt findLiveBolt(final World world) { - for (final Entity entity : world.loadedEntityList) { - if (entity instanceof EntityCustomBolt && !entity.isDead) { - return (EntityCustomBolt) entity; - } - } - return null; - } - - private static int verifyArmorEffects(final MinecraftServer server) { - final WorldServer world = server.getWorld(0); - int checked = 0; - - for (int pieces = 1; pieces <= 4; pieces++) { - final EntityPlayer player = armorTestPlayer(server, world, - "StarSteel" + pieces); - final ItemStack trigger = equipArmor(player, MaterialNames.STARSTEEL, pieces); - Materials.getMaterialByName(MaterialNames.STARSTEEL).applyEffect(trigger, player); - requireEffect(player, MobEffects.JUMP_BOOST, pieces - 1, - "Star-Steel " + pieces + "-piece jump boost"); - if (pieces == 1) { - requireNoEffect(player, MobEffects.SPEED, - "Star-Steel one-piece speed boost"); - } else { - requireEffect(player, MobEffects.SPEED, pieces - 2, - "Star-Steel " + pieces + "-piece speed boost"); - } - checked += 2; - } - - for (int pieces = 1; pieces <= 4; pieces++) { - final EntityPlayer player = armorTestPlayer(server, world, - "Adamantine" + pieces); - final ItemStack trigger = equipArmor(player, MaterialNames.ADAMANTINE, pieces); - Materials.getMaterialByName(MaterialNames.ADAMANTINE).applyEffect(trigger, player); - if (pieces == 1) { - requireNoEffect(player, MobEffects.RESISTANCE, - "Adamantine one-piece resistance"); - } else { - requireEffect(player, MobEffects.RESISTANCE, pieces == 4 ? 1 : 0, - "Adamantine " + pieces + "-piece resistance"); - } - checked++; - } - - for (int pieces = 1; pieces <= 4; pieces++) { - final EntityPlayer player = armorTestPlayer(server, world, - "Lead" + pieces); - final ItemStack trigger = equipArmor(player, MaterialNames.LEAD, pieces); - Materials.getMaterialByName(MaterialNames.LEAD).applyEffect(trigger, player); - if (pieces == 1) { - requireNoEffect(player, MobEffects.SLOWNESS, - "Lead one-piece slowness"); - } else { - requireEffect(player, MobEffects.SLOWNESS, pieces == 4 ? 1 : 0, - "Lead " + pieces + "-piece slowness"); - } - checked++; - } - - final EntityPlayer coldIronPartial = armorTestPlayer(server, world, - "ColdIronPartial"); - final ItemStack coldIronPartialTrigger = equipArmor( - coldIronPartial, MaterialNames.COLDIRON, 3); - Materials.getMaterialByName(MaterialNames.COLDIRON) - .applyEffect(coldIronPartialTrigger, coldIronPartial); - requireNoEffect(coldIronPartial, MobEffects.FIRE_RESISTANCE, - "Cold-Iron partial-suit fire resistance"); - checked++; - - final EntityPlayer coldIronFull = armorTestPlayer(server, world, - "ColdIronFull"); - final ItemStack coldIronFullTrigger = equipArmor( - coldIronFull, MaterialNames.COLDIRON, 4); - Materials.getMaterialByName(MaterialNames.COLDIRON) - .applyEffect(coldIronFullTrigger, coldIronFull); - requireEffect(coldIronFull, MobEffects.FIRE_RESISTANCE, 0, - "Cold-Iron full-suit fire resistance"); - checked++; - - final EntityPlayer mithrilPartial = armorTestPlayer(server, world, - "MithrilPartial"); - final ItemStack mithrilPartialTrigger = equipArmor( - mithrilPartial, MaterialNames.MITHRIL, 3); - mithrilPartial.addPotionEffect(new PotionEffect(MobEffects.POISON, 200, 0)); - Materials.getMaterialByName(MaterialNames.MITHRIL) - .applyEffect(mithrilPartialTrigger, mithrilPartial); - requireEffect(mithrilPartial, MobEffects.POISON, 0, - "Mithril partial-suit harmful-effect preservation"); - checked++; - - final EntityPlayer mithrilFull = armorTestPlayer(server, world, - "MithrilFull"); - final ItemStack mithrilFullTrigger = equipArmor( - mithrilFull, MaterialNames.MITHRIL, 4); - mithrilFull.addPotionEffect(new PotionEffect(MobEffects.POISON, 200, 0)); - Materials.getMaterialByName(MaterialNames.MITHRIL) - .applyEffect(mithrilFullTrigger, mithrilFull); - requireNoEffect(mithrilFull, MobEffects.POISON, - "Mithril full-suit harmful-effect removal"); - checked++; - - final BlockPos waterFeet = new BlockPos(24, 80, 24); - final BlockPos waterHead = waterFeet.up(); - final net.minecraft.block.state.IBlockState originalFeet = world.getBlockState(waterFeet); - final net.minecraft.block.state.IBlockState originalHead = world.getBlockState(waterHead); - try { - world.setBlockState(waterFeet, Blocks.FLOWING_WATER.getDefaultState(), 2); - world.setBlockState(waterHead, Blocks.FLOWING_WATER.getDefaultState(), 2); - - final EntityPlayer aquariumPartial = armorTestPlayer(server, world, - "AquariumPartial"); - aquariumPartial.setPosition(24.5D, 80.0D, 24.5D); - aquariumPartial.handleWaterMovement(); - final ItemStack aquariumPartialTrigger = equipArmor( - aquariumPartial, MaterialNames.AQUARIUM, 3); - Materials.getMaterialByName(MaterialNames.AQUARIUM) - .applyEffect(aquariumPartialTrigger, aquariumPartial); - requireNoEffect(aquariumPartial, MobEffects.WATER_BREATHING, - "Aquarium partial-suit water breathing"); - checked++; - - final EntityPlayer aquariumFull = armorTestPlayer(server, world, - "AquariumFull"); - aquariumFull.setPosition(24.5D, 80.0D, 24.5D); - aquariumFull.handleWaterMovement(); - final ItemStack aquariumFullTrigger = equipArmor( - aquariumFull, MaterialNames.AQUARIUM, 4); - aquariumFull.addPotionEffect(new PotionEffect(MobEffects.MINING_FATIGUE, 200, 0)); - Materials.getMaterialByName(MaterialNames.AQUARIUM) - .applyEffect(aquariumFullTrigger, aquariumFull); - requireEffect(aquariumFull, MobEffects.WATER_BREATHING, 0, - "Aquarium full-suit water breathing"); - requireEffect(aquariumFull, MobEffects.RESISTANCE, 0, - "Aquarium full-suit resistance"); - requireNoEffect(aquariumFull, MobEffects.MINING_FATIGUE, - "Aquarium full-suit mining-fatigue removal"); - checked += 3; - } finally { - world.setBlockState(waterFeet, originalFeet, 2); - world.setBlockState(waterHead, originalHead, 2); - } - - final EntityPlayer aquariumDry = armorTestPlayer(server, world, - "AquariumDry"); - aquariumDry.setPosition(24.5D, 82.0D, 24.5D); - final ItemStack aquariumDryTrigger = equipArmor( - aquariumDry, MaterialNames.AQUARIUM, 4); - Materials.getMaterialByName(MaterialNames.AQUARIUM) - .applyEffect(aquariumDryTrigger, aquariumDry); - requireNoEffect(aquariumDry, MobEffects.WATER_BREATHING, - "Aquarium dry full-suit water breathing"); - checked++; - - require(!new ColdIronProperty().hasEffect( - new ItemStack(net.minecraft.init.Items.DIAMOND), coldIronFull), - "Cold-Iron property accepts an unrelated item"); - checked++; - - final EntityPlayer starSteelContract = armorTestPlayer(server, world, - "StarSteelContract"); - final ItemStack starSteelContractTrigger = equipArmor( - starSteelContract, MaterialNames.STARSTEEL, 1); - require(new StarSteelProperty().hasEffect( - starSteelContractTrigger, starSteelContract), - "Star-Steel property rejected its own equipped armor"); - checked++; - - final EntityPlayer starSteelTickPlayer = armorTestPlayer(server, world, - "StarSteelArmorTick"); - final ItemStack starSteelTickTrigger = equipArmor( - starSteelTickPlayer, MaterialNames.STARSTEEL, 4); - if (world.getTotalWorldTime() == 0L) { - world.getWorldInfo().setWorldTotalTime(1L); - } - starSteelTickTrigger.getItem().onArmorTick( - world, starSteelTickPlayer, starSteelTickTrigger); - starSteelTickTrigger.getItem().onArmorTick( - world, starSteelTickPlayer, starSteelTickTrigger); - requireEffect(starSteelTickPlayer, MobEffects.JUMP_BOOST, 3, - "Star-Steel armor-tick jump boost"); - requireEffect(starSteelTickPlayer, MobEffects.SPEED, 2, - "Star-Steel armor-tick speed boost"); - checked += 2; - - final BlockPos tickWaterFeet = new BlockPos(28, 80, 28); - final BlockPos tickWaterHead = tickWaterFeet.up(); - final net.minecraft.block.state.IBlockState originalTickFeet = - world.getBlockState(tickWaterFeet); - final net.minecraft.block.state.IBlockState originalTickHead = - world.getBlockState(tickWaterHead); - try { - world.setBlockState(tickWaterFeet, Blocks.WATER.getDefaultState(), 2); - world.setBlockState(tickWaterHead, Blocks.WATER.getDefaultState(), 2); - final EntityPlayer aquariumTickPlayer = armorTestPlayer(server, world, - "AquariumArmorTick"); - aquariumTickPlayer.setPosition(28.5D, 80.0D, 28.5D); - aquariumTickPlayer.handleWaterMovement(); - final ItemStack aquariumTickTrigger = equipArmor( - aquariumTickPlayer, MaterialNames.AQUARIUM, 4); - aquariumTickTrigger.getItem().onArmorTick( - world, aquariumTickPlayer, aquariumTickTrigger); - aquariumTickTrigger.getItem().onArmorTick( - world, aquariumTickPlayer, aquariumTickTrigger); - requireEffect(aquariumTickPlayer, MobEffects.WATER_BREATHING, 0, - "Aquarium armor-tick water breathing"); - requireEffect(aquariumTickPlayer, MobEffects.RESISTANCE, 0, - "Aquarium armor-tick resistance"); - checked += 2; - } finally { - world.setBlockState(tickWaterFeet, originalTickFeet, 2); - world.setBlockState(tickWaterHead, originalTickHead, 2); - } - - return checked; - } - - private static EntityPlayer armorTestPlayer( - final MinecraftServer server, - final WorldServer world, - final String name) { - return new ProbePlayer(world, - new GameProfile(UUID.nameUUIDFromBytes(name.getBytes()), name)); - } - - private static ItemStack equipArmor( - final EntityPlayer player, - final String materialName, - final int pieces) { - final MMDMaterial material = Materials.getMaterialByName(materialName); - final EntityEquipmentSlot[] slots = { - EntityEquipmentSlot.FEET, - EntityEquipmentSlot.LEGS, - EntityEquipmentSlot.CHEST, - EntityEquipmentSlot.HEAD - }; - final Names[] forms = { - Names.BOOTS, - Names.LEGGINGS, - Names.CHESTPLATE, - Names.HELMET - }; - ItemStack trigger = ItemStack.EMPTY; - for (int i = 0; i < pieces; i++) { - final ItemStack armor = new ItemStack(material.getItem(forms[i])); - player.setItemStackToSlot(slots[i], armor); - if (trigger.isEmpty()) { - trigger = armor; - } - } - return trigger; - } - - private static void requireEffect( - final EntityPlayer player, - final net.minecraft.potion.Potion potion, - final int amplifier, - final String description) { - final PotionEffect effect = player.getActivePotionEffect(potion); - require(effect != null, description + " was not applied"); - require(effect.getAmplifier() == amplifier, - description + " has amplifier " + effect.getAmplifier() - + ", expected " + amplifier); - } - - private static void requireNoEffect( - final EntityPlayer player, - final net.minecraft.potion.Potion potion, - final String description) { - require(player.getActivePotionEffect(potion) == null, - description + " was unexpectedly applied"); - } - - private static final class ProbePlayer extends EntityPlayer { - private ProbePlayer(final World world, final GameProfile profile) { - super(world, profile); - } - - @Override - public boolean isSpectator() { - return false; - } - - @Override - public boolean isCreative() { - return false; - } - } - - private static void verifyRailRecipe( - final World world, - final String recipePath, - final Item expectedItem, - final int expectedCount, - final Item... grid) { - require(grid.length == 9, "Rail recipe test grid must contain nine slots"); - final InventoryCrafting crafting = new InventoryCrafting(new Container() { - @Override - public boolean canInteractWith(final EntityPlayer playerIn) { - return false; - } - }, 3, 3); - for (int slot = 0; slot < grid.length; slot++) { - if (grid[slot] != null) { - crafting.setInventorySlotContents(slot, new ItemStack(grid[slot])); - } - } - - final ResourceLocation expectedRecipe = new ResourceLocation("basemetals", recipePath); - final IRecipe registeredRecipe = CraftingManager.REGISTRY.getObject(expectedRecipe); - require(registeredRecipe != null, "Crafting recipe was not registered: " + expectedRecipe); - require(registeredRecipe.matches(crafting, world), - "Registered crafting recipe did not match its canonical input: " + expectedRecipe); - final IRecipe recipe = CraftingManager.findMatchingRecipe(crafting, world); - require(recipe != null, "No crafting recipe matched " + expectedRecipe); - require(expectedRecipe.equals(recipe.getRegistryName()), - "Crafting input for " + expectedRecipe + " matched " + recipe.getRegistryName()); - - final ItemStack result = recipe.getCraftingResult(crafting); - require(!result.isEmpty(), "Crafting recipe " + expectedRecipe + " returned an empty result"); - require(result.getItem() == expectedItem, - "Crafting recipe " + expectedRecipe + " returned " + result.getItem().getRegistryName() - + ", expected " + expectedItem.getRegistryName()); - require(result.getCount() == expectedCount, - "Crafting recipe " + expectedRecipe + " returned " + result.getCount() - + " items, expected " + expectedCount); - } - - private static int verifyDoorAndTrapdoorRecipe( - final World world, - final Item ingredient, - final String material) { - requireCreativeRegistryEntry(material + "_door"); - requireCreativeRegistryEntry(material + "_trapdoor"); - verifyCraftingResult(world, ingredient, material + "_door", 3, 2, 3); - if ("quartz".equals(material)) { - verifyCraftingResult(world, Item.getItemFromBlock(Blocks.QUARTZ_BLOCK), - material + "_trapdoor", 1, 1, 1); - } else { - verifyCraftingResult(world, ingredient, material + "_trapdoor", 1, 2, 2); - } - return 2; - } - - private static void requireCreativeRegistryEntry(final String path) { - final ResourceLocation registryName = new ResourceLocation("basemetals", path); - final Block block = Block.REGISTRY.getObject(registryName); - require(block != null && registryName.equals(block.getRegistryName()), - "Missing registered block " + registryName); - final Item item = Item.REGISTRY.getObject(registryName); - require(item != null && registryName.equals(item.getRegistryName()), - "Missing registered item " + registryName); - require(item.getCreativeTab() != null, - "Registered item is absent from creative tabs: " + registryName); - } - - private static void verifyCraftingResult( - final World world, - final Item ingredient, - final String expectedPath, - final int expectedCount, - final int width, - final int height) { - final InventoryCrafting crafting = new InventoryCrafting(new Container() { - @Override - public boolean canInteractWith(final EntityPlayer playerIn) { - return false; - } - }, 3, 3); - for (int row = 0; row < height; row++) { - for (int column = 0; column < width; column++) { - crafting.setInventorySlotContents(column + row * 3, new ItemStack(ingredient)); - } - } - - final ResourceLocation expectedRecipe = new ResourceLocation("basemetals", expectedPath); - final IRecipe registeredRecipe = CraftingManager.REGISTRY.getObject(expectedRecipe); - require(registeredRecipe != null, "Crafting recipe was not registered: " + expectedRecipe); - require(registeredRecipe.matches(crafting, world), - "Registered crafting recipe did not match its canonical input: " + expectedRecipe); - final IRecipe recipe = CraftingManager.findMatchingRecipe(crafting, world); - require(recipe != null, "No crafting recipe matched " + expectedRecipe); - require(expectedRecipe.equals(recipe.getRegistryName()), - "Crafting input for " + expectedRecipe + " matched " + recipe.getRegistryName()); - - final ItemStack result = recipe.getCraftingResult(crafting); - require(!result.isEmpty(), "Crafting recipe " + expectedRecipe + " returned an empty result"); - require(expectedRecipe.equals(result.getItem().getRegistryName()), - "Crafting recipe " + expectedRecipe + " returned " + result.getItem().getRegistryName()); - require(result.getCount() == expectedCount, - "Crafting recipe " + expectedRecipe + " returned " + result.getCount() - + " items, expected " + expectedCount); - } - - private static String requiredProperty(final String name) { - final String value = System.getProperty(name); - if (value == null || value.trim().isEmpty()) { - throw new IllegalStateException("Missing system property " + name); - } - return value; - } - - private static String version(final String modid) { - for (final ModContainer mod : Loader.instance().getModList()) { - if (modid.equals(mod.getModId())) { - return mod.getVersion(); - } - } - throw new IllegalStateException("Missing loaded mod " + modid); - } - - private static Item requireItem(final String namespace, final String path) { - final ResourceLocation registryName = new ResourceLocation(namespace, path); - final Item item = Item.REGISTRY.getObject(registryName); - require(item != null && registryName.equals(item.getRegistryName()), - "Missing registered item " + registryName); - return item; - } - - private static void requireRegistered(final Object value, final String registryName) { - require(value != null, "Missing registry object " + registryName); - } - - private static void require(final boolean condition, final String message) { - if (!condition) { - throw new IllegalStateException(message); - } - } + + return checked; + } + + private static int verifyAncientWarfareHoes(final World world) { + try { + final Class workerClass = Class.forName( + "net.shadowmage.ancientwarfare.npc.entity.NpcWorker"); + final Class workTypeClass = Class.forName( + "net.shadowmage.ancientwarfare.core.interfaces.IWorkSite$WorkType"); + final Object farming = enumConstant(workTypeClass, "FARMING"); + final Method effectivenessMethod = workerClass.getMethod( + "getWorkEffectiveness", workTypeClass); + int checked = 0; + + for (final String path : new String[]{ + "emerald_hoe", "steel_hoe", "adamantine_hoe"}) { + final EntityLivingBase worker = (EntityLivingBase) workerClass + .getConstructor(World.class).newInstance(world); + + worker.setHeldItem(EnumHand.MAIN_HAND, + new ItemStack(requireItem("basemetals", path))); + + final float effectiveness = ((Number) effectivenessMethod + .invoke(worker, farming)).floatValue(); + + require(!Float.isNaN(effectiveness) && !Float.isInfinite(effectiveness) + && effectiveness > 0.0F, + "Ancient Warfare returned invalid work effectiveness " + + effectiveness + " for basemetals:" + path); + checked++; + } + + require(checked == 3, + "Checked " + checked + " Ancient Warfare hoes, expected 3"); + + return checked; + } catch (final InvocationTargetException exception) { + throw new IllegalStateException("Ancient Warfare rejected a Base Metals hoe", + exception.getCause()); + } catch (final ReflectiveOperationException exception) { + throw new IllegalStateException( + "Could not exercise Ancient Warfare's farming effectiveness path", exception); + } + } + + private static Object enumConstant(final Class enumClass, final String name) { + for (final Object constant : enumClass.getEnumConstants()) { + if (((Enum) constant).name().equals(name)) { + return constant; + } + } + + throw new IllegalStateException("Missing enum constant " + enumClass.getName() + "." + name); + } + + private static boolean isNuggetOrPowder(final String path) { + return path.endsWith("_nugget") + || path.endsWith("_powder") + || path.endsWith("_smallpowder"); + } + + private static int expectedBurnTime(final String path) { + if (path.startsWith("coal_") || path.startsWith("charcoal_")) { + return path.endsWith("_powder") ? 1600 : 200; + } + + return 0; + } + + private static int verifyDoorAndTrapdoorRecipes(final World world) { + int checked = 0; + + checked += verifyDoorAndTrapdoorRecipe(world, net.minecraft.init.Items.DIAMOND, "diamond"); + checked += verifyDoorAndTrapdoorRecipe(world, net.minecraft.init.Items.EMERALD, "emerald"); + checked += verifyDoorAndTrapdoorRecipe(world, net.minecraft.init.Items.GOLD_INGOT, "gold"); + checked += verifyDoorAndTrapdoorRecipe(world, net.minecraft.init.Items.QUARTZ, "quartz"); + + return checked; + } + + private static int verifyRailRecipes(final World world) { + final Item steel = requireItem("basemetals", "steel_ingot"); + final Item stick = net.minecraft.init.Items.STICK; + final Item redstone = net.minecraft.init.Items.REDSTONE; + final Item redstoneTorch = Item.getItemFromBlock(Blocks.REDSTONE_TORCH); + final Item stonePressurePlate = Item.getItemFromBlock(Blocks.STONE_PRESSURE_PLATE); + + verifyRailRecipe(world, "rail", Item.getItemFromBlock(Blocks.RAIL), 16, + steel, null, steel, + steel, stick, steel, + steel, null, steel); + verifyRailRecipe(world, "activator_rail", Item.getItemFromBlock(Blocks.ACTIVATOR_RAIL), 6, + steel, stick, steel, + steel, redstoneTorch, steel, + steel, stick, steel); + verifyRailRecipe(world, "detector_rail", Item.getItemFromBlock(Blocks.DETECTOR_RAIL), 6, + steel, null, steel, + steel, stonePressurePlate, steel, + steel, redstone, steel); + + return 3; + } + + private static int verifyPlateRepairRecipes(final MinecraftServer server) { + final World world = server.getEntityWorld(); + final List defects = new ArrayList<>(); + int checked = 0; + int dormant = 0; + + for (final IRecipe recipe : CraftingManager.REGISTRY) { + final ResourceLocation id = recipe.getRegistryName(); + + if (id == null || !"basemetals".equals(id.getNamespace()) + || !id.getPath().endsWith("_plate_repair")) { + continue; + } + + checked++; + + if (!(recipe instanceof PlateRepairRecipe)) { + defects.add(id + " does not use the Base Metals repair matcher"); + continue; + } + + if (!recipe.isDynamic()) { + defects.add(id + " is exposed as a recipe-book crafting recipe"); + } + + if (server.getAdvancementManager().getAdvancement(new ResourceLocation( + "basemetals", "recipes/materials/" + id.getPath())) != null) { + defects.add(id + " still has a generated recipe-book advancement"); + } + + if (recipe.getIngredients().size() != 2 + || recipe.getIngredients().get(0).getMatchingStacks().length == 0) { + defects.add(id + " does not present the damaged item to recipe viewers"); + continue; + } + + if (recipe.getIngredients().get(1).getMatchingStacks().length == 0) { + // Vanilla Bits does not register diamond or emerald plates. Their + // legacy repair IDs remain available if another mod adds those plates. + if (!id.getPath().startsWith("diamond_") + && !id.getPath().startsWith("emerald_")) { + defects.add(id + " lacks its matching plate"); + } + + if (recipe.matches(plateRepairGrid(recipe.getRecipeOutput(), 0, + new ItemStack(net.minecraft.init.Items.STICK), 1, null, -1), world)) { + defects.add(id + " accepts an unrelated item in place of an absent plate"); + } + + dormant++; + continue; + } + + final ItemStack damaged = recipe.getRecipeOutput().copy(); + + damaged.setItemDamage(1); + + final NBTTagCompound tag = new NBTTagCompound(); + + tag.setString("BaseMetalsRepairProbe", "kept"); + damaged.setTagCompound(tag); + damaged.addEnchantment(Enchantments.UNBREAKING, 1); + + final ItemStack plate = recipe.getIngredients().get(1).getMatchingStacks()[0].copy(); + final InventoryCrafting shifted = plateRepairGrid(damaged, 4, plate, 5, null, -1); + + if (!recipe.matches(shifted, world)) { + defects.add(id + " fails with leading empty slots"); + } + + final InventoryCrafting swapped = plateRepairGrid(damaged, 8, plate, 0, null, -1); + + if (!recipe.matches(swapped, world)) { + defects.add(id + " fails with plate before armor"); + } + + final InventoryCrafting canonical = plateRepairGrid(damaged, 0, plate, 1, null, -1); + + if (!recipe.matches(canonical, world)) { + defects.add(id + " fails with canonical input"); + } else { + final ItemStack repaired = recipe.getCraftingResult(canonical); + + if (repaired.isEmpty() || repaired.getItem() != damaged.getItem() + || repaired.getItemDamage() != 0 || repaired.getCount() != 1 + || !ItemStack.areItemStackTagsEqual(repaired, damaged) + || damaged.getItemDamage() != 1) { + defects.add(id + " does not preserve the original stack and all its NBT"); + } + } + + final ItemStack undamaged = damaged.copy(); + + undamaged.setItemDamage(0); + + if (recipe.matches(plateRepairGrid(undamaged, 0, plate, 1, null, -1), world) + || recipe.matches(plateRepairGrid(null, -1, plate, 1, null, -1), world) + || recipe.matches(plateRepairGrid(damaged, 0, null, -1, null, -1), world) + || recipe.matches(plateRepairGrid(damaged, 0, plate, 1, + new ItemStack(net.minecraft.init.Items.STICK), 2), world) + || recipe.matches(plateRepairGrid(damaged, 0, plate, 1, plate, 2), world)) { + defects.add(id + " accepts missing, undamaged, or extra inputs"); + } + } + + require(checked == 110, "Expected 110 plate repair recipes, found " + checked); + require(dormant == 10, "Expected ten dormant diamond/emerald recipes, found " + dormant); + + final IRecipe iron = CraftingManager.REGISTRY.getObject(new ResourceLocation( + "basemetals", "iron_chestplate_plate_repair")); + final ItemStack ironArmor = new ItemStack(net.minecraft.init.Items.IRON_CHESTPLATE); + + ironArmor.setItemDamage(1); + + final ItemStack wrongPlate = new ItemStack(requireItem("basemetals", "copper_plate")); + + if (iron.matches(plateRepairGrid(ironArmor, 0, wrongPlate, 1, null, -1), world)) { + defects.add("iron armor accepts a mismatched plate"); + } + + // An upgraded player's saved recipe book may still contain the old ID. + // Minecraft refuses to re-unlock a recipe after it becomes dynamic. + final NBTTagCompound oldRecipeBook = new NBTTagCompound(); + final NBTTagList unlocked = new NBTTagList(); + + unlocked.appendTag(new NBTTagString("basemetals:iron_chestplate_plate_repair")); + oldRecipeBook.setTag("recipes", unlocked); + + final RecipeBookServer upgraded = new RecipeBookServer(); + + upgraded.read(oldRecipeBook); + + if (upgraded.isUnlocked(iron) || !iron.isDynamic()) { + defects.add("old saved repair unlock remains visible after loading"); + } + + require(defects.isEmpty(), "Plate repair defects: " + defects); + + return checked; + } + + private static int verifyPlateRepairsDisabled() { + int checked = 0; + + for (final IRecipe recipe : CraftingManager.REGISTRY) { + final ResourceLocation id = recipe.getRegistryName(); + + if (id != null && "basemetals".equals(id.getNamespace()) + && id.getPath().endsWith("_plate_repair")) { + checked++; + } + } + + require(checked == 0, + "Plate repairs were registered despite MMDLib repair_using_plates=false: " + + checked); + + return 0; + } + + private static InventoryCrafting plateRepairGrid(final ItemStack armor, final int armorSlot, + final ItemStack plate, final int plateSlot, final ItemStack extra, final int extraSlot) { + final InventoryCrafting grid = new InventoryCrafting(new Container() { + @Override + public boolean canInteractWith(final EntityPlayer playerIn) { + return false; + } + }, 3, 3); + + if (armor != null && armorSlot >= 0) { + grid.setInventorySlotContents(armorSlot, armor.copy()); + } + + if (plate != null && plateSlot >= 0) { + grid.setInventorySlotContents(plateSlot, plate.copy()); + } + + if (extra != null && extraSlot >= 0) { + grid.setInventorySlotContents(extraSlot, extra.copy()); + } + + return grid; + } + + private static int verifyRailRecipeAdvancement(final MinecraftServer server) { + final ResourceLocation advancementId = new ResourceLocation( + "basemetals", "recipes/transportation/rail"); + final Advancement advancement = server.getAdvancementManager().getAdvancement(advancementId); + + require(advancement != null, "Recipe-book advancement was not loaded: " + advancementId); + require(advancement.getCriteria().containsKey("has_iron_ingot"), + advancementId + " does not recognize iron ingots"); + require(advancement.getCriteria().containsKey("has_steel_ingot"), + advancementId + " does not recognize Base Metals steel ingots"); + require(advancement.getCriteria().containsKey("has_the_recipe"), + advancementId + " lacks its recipe-unlocked criterion"); + require(advancement.getRequirements().length == 1 + && advancement.getRequirements()[0].length == 3, + advancementId + " discovery criteria are not alternatives"); + + return 1; + } + + private static int verifyMaterialRecipeAdvancements(final MinecraftServer server) { + final String[] recipes = { + "coldiron_block", "coldiron_pickaxe", "coldiron_chestplate", + "coldiron_bow", "coldiron_door" + }; + + for (final String recipe : recipes) { + final ResourceLocation advancementId = new ResourceLocation( + "basemetals", "recipes/materials/coldiron/" + recipe); + final Advancement advancement = server.getAdvancementManager() + .getAdvancement(advancementId); + + require(advancement != null, + "Material recipe-book advancement was not loaded: " + advancementId); + require(advancement.getCriteria().containsKey("has_material"), + advancementId + " lacks its material discovery criterion"); + require(advancement.getCriteria().containsKey("has_the_recipe"), + advancementId + " lacks its recipe-unlocked criterion"); + require(advancement.getRequirements().length == 1 + && advancement.getRequirements()[0].length == 2, + advancementId + " discovery criteria are not alternatives"); + } + + return recipes.length; + } + + private static int verifyCrossbowBoltImpact(final MinecraftServer server) { + final WorldServer world = server.getWorld(0); + final Item crossbow = requireItem("basemetals", "steel_crossbow"); + final Item boltItem = requireItem("basemetals", "steel_bolt"); + final ItemStack crossbowStack = new ItemStack(crossbow); + final ItemStack ammunition = new ItemStack(boltItem); + final EntityPlayerMP shooter = new EntityPlayerMP(server, world, + new GameProfile(UUID.randomUUID(), "BaseMetalsBoltProbe"), + new PlayerInteractionManager(world)); + final BlockPos spawn = world.getSpawnPoint(); + final double x = spawn.getX() + 0.5D; + final double y = spawn.getY() + 16.0D; + final double z = spawn.getZ() + 0.5D; + + shooter.setPositionAndRotation(x, y, z, 0.0F, 0.0F); + shooter.setHeldItem(EnumHand.OFF_HAND, ammunition); + + final EntityIronGolem target = new EntityIronGolem(world); + + target.setPosition(x, y, z + 2.5D); + require(world.spawnEntity(target), "Could not spawn the crossbow impact target"); + + final float healthBefore = target.getHealth(); + final int boltsBefore = countBolts(world); + EntityCustomBolt projectile = null; + + try { + crossbow.onPlayerStoppedUsing(crossbowStack, world, shooter, + crossbow.getMaxItemUseDuration(crossbowStack) - 20); + require(countBolts(world) == boltsBefore + 1, + "Base Metals crossbow did not create a server-side bolt"); + projectile = findLiveBolt(world); + require(projectile != null, "Spawned Base Metals bolt could not be located"); + + final MMDMaterial steel = Materials.getMaterialByName(MaterialNames.STEEL); + + requireDamage(steel.getBaseAttackDamage() * 2.0D, projectile.getDamage(), + "steel crossbow and bolt impact projectile"); + + final ItemStack savedAmmunition = EntityHelpers.readFromNBTItemStack( + projectile.writeToNBT(new NBTTagCompound())); + + require(savedAmmunition.getItem() == boltItem && savedAmmunition.getCount() == 1, + "Base Metals bolt did not preserve its ammunition item"); + + for (int tick = 0; tick < 4 && target.getHealth() == healthBefore; tick++) { + projectile.onUpdate(); + } + + require(target.getHealth() < healthBefore, + "Base Metals crossbow bolt did not damage its target"); + require(ammunition.isEmpty(), + "Base Metals crossbow consumed an unexpected number of bolts"); + require(crossbowStack.getItemDamage() == 1, + "Base Metals crossbow did not lose one durability after firing"); + } finally { + if (projectile != null) { + projectile.setDead(); + } + + target.setDead(); + } + + return 1; + } + + private static int verifyBowArrowImpact(final MinecraftServer server) { + final WorldServer world = server.getWorld(0); + final Item bow = requireItem("basemetals", "steel_bow"); + final Item arrowItem = requireItem("basemetals", "steel_arrow"); + final ItemStack bowStack = new ItemStack(bow); + final ItemStack ammunition = new ItemStack(arrowItem); + final EntityPlayerMP shooter = new EntityPlayerMP(server, world, + new GameProfile(UUID.randomUUID(), "BaseMetalsArrowProbe"), + new PlayerInteractionManager(world)); + final BlockPos spawn = world.getSpawnPoint(); + final double x = spawn.getX() + 0.5D; + final double y = spawn.getY() + 16.0D; + final double z = spawn.getZ() + 0.5D; + + shooter.setPositionAndRotation(x, y, z, 0.0F, 0.0F); + shooter.setHeldItem(EnumHand.OFF_HAND, ammunition); + + final EntityIronGolem target = new EntityIronGolem(world); + + target.setPosition(x, y, z + 2.5D); + require(world.spawnEntity(target), "Could not spawn the bow impact target"); + + final float healthBefore = target.getHealth(); + final int arrowsBefore = countArrows(world); + EntityArrow projectile = null; + + try { + bow.onPlayerStoppedUsing(bowStack, world, shooter, + bow.getMaxItemUseDuration(bowStack) - 20); + require(countArrows(world) == arrowsBefore + 1, + "Base Metals bow did not create a server-side arrow"); + projectile = findLiveArrow(world); + require(projectile != null, "Spawned Base Metals arrow could not be located"); + + final MMDMaterial steel = Materials.getMaterialByName(MaterialNames.STEEL); + + requireDamage(steel.getBaseAttackDamage() * 2.0D, projectile.getDamage(), + "steel bow and arrow impact projectile"); + + final ItemStack savedAmmunition = EntityHelpers.readFromNBTItemStack( + projectile.writeToNBT(new NBTTagCompound())); + + require(savedAmmunition.getItem() == arrowItem && savedAmmunition.getCount() == 1, + "Base Metals arrow did not preserve its ammunition item"); + + for (int tick = 0; tick < 4 && target.getHealth() == healthBefore; tick++) { + projectile.onUpdate(); + } + + require(target.getHealth() < healthBefore, + "Base Metals bow arrow did not damage its target"); + require(ammunition.isEmpty(), + "Base Metals bow consumed an unexpected number of arrows"); + require(bowStack.getItemDamage() == 1, + "Base Metals bow did not lose one durability after firing"); + } finally { + if (projectile != null) { + projectile.setDead(); + } + + target.setDead(); + } + + return 1; + } + + private static int verifyArrowPickupIdentity(final MinecraftServer server) { + final WorldServer world = server.getWorld(0); + final EntityPlayerMP shooter = new EntityPlayerMP(server, world, + new GameProfile(UUID.randomUUID(), "BaseMetalsArrowIdentityProbe"), + new PlayerInteractionManager(world)); + final BlockPos spawn = world.getSpawnPoint(); + + shooter.setPositionAndRotation(spawn.getX() + 0.5D, spawn.getY() + 16.0D, + spawn.getZ() + 0.5D, 0.0F, 0.0F); + + int checked = 0; + + for (final MMDMaterial material : Materials.getAllMaterials()) { + if (!isBaseMetalsItem(material, Names.ARROW)) { + continue; + } + + final Item arrowItem = material.getItem(Names.ARROW); + final ItemStack inventoryAmmunition = new ItemStack(arrowItem); + final EntityCustomArrow projectile = ((ItemBaseMetalsArrow) arrowItem) + .createArrow(world, inventoryAmmunition, shooter); + + inventoryAmmunition.shrink(1); + require(inventoryAmmunition.isEmpty(), + arrowItem.getRegistryName() + " identity test did not consume its source stack"); + + final NBTTagCompound saved = projectile.writeToNBT(new NBTTagCompound()); + final ItemStack pickup = EntityHelpers.readFromNBTItemStack(saved); + + require(pickup.getItem() == arrowItem && pickup.getCount() == 1, + arrowItem.getRegistryName() + " became another item before pickup"); + + final EntityCustomArrow reloaded = new EntityCustomArrow(world); + + reloaded.readFromNBT(saved); + + final ItemStack reloadedPickup = EntityHelpers.readFromNBTItemStack( + reloaded.writeToNBT(new NBTTagCompound())); + + require(reloadedPickup.getItem() == arrowItem && reloadedPickup.getCount() == 1, + arrowItem.getRegistryName() + " lost its identity after save and reload"); + projectile.setDead(); + reloaded.setDead(); + checked++; + } + + require(checked == 27, + "Checked " + checked + " Base Metals arrow identities, expected 27"); + + final Item arrowItem = requireItem("basemetals", "steel_arrow"); + final ItemStack ammunition = new ItemStack(arrowItem); + final ItemStack vanillaBow = new ItemStack(net.minecraft.init.Items.BOW); + + shooter.setHeldItem(EnumHand.OFF_HAND, ammunition); + + final int arrowsBefore = countArrows(world); + EntityArrow projectile = null; + + try { + net.minecraft.init.Items.BOW.onPlayerStoppedUsing(vanillaBow, world, shooter, + vanillaBow.getMaxItemUseDuration() - 20); + require(countArrows(world) == arrowsBefore + 1, + "Vanilla bow did not create a Base Metals arrow projectile"); + projectile = findLiveArrow(world); + require(projectile instanceof EntityCustomArrow, + "Vanilla bow did not retain the Base Metals arrow entity"); + require(ammunition.isEmpty(), + "Vanilla bow did not consume the last Base Metals arrow"); + + final ItemStack pickup = EntityHelpers.readFromNBTItemStack( + projectile.writeToNBT(new NBTTagCompound())); + + require(pickup.getItem() == arrowItem && pickup.getCount() == 1, + "Vanilla bow changed a Base Metals arrow into another pickup item"); + } finally { + if (projectile != null) { + projectile.setDead(); + } + } + + return checked + 1; + } + + private static int verifyCrossbowRegistrations() { + int checked = 0; + + for (final MMDMaterial material : Materials.getAllMaterials()) { + if (!material.hasItem(Names.CROSSBOW)) { + continue; + } + + final Item crossbow = material.getItem(Names.CROSSBOW); + final ResourceLocation registryName = crossbow.getRegistryName(); + + if (registryName == null || !"basemetals".equals(registryName.getNamespace())) { + continue; + } + + require(crossbow instanceof ItemBaseMetalsCrossbow, + registryName + " does not use the corrected Base Metals crossbow implementation"); + checked++; + } + + require(checked == 27, "Checked " + checked + " Base Metals crossbows, expected 27"); + + return checked; + } + + private static int verifyRangedItemRegistrations() { + int arrows = 0; + int bolts = 0; + int bows = 0; + + for (final MMDMaterial material : Materials.getAllMaterials()) { + if (isBaseMetalsItem(material, Names.ARROW)) { + require(material.getItem(Names.ARROW) instanceof ItemBaseMetalsArrow, + material.getItem(Names.ARROW).getRegistryName() + + " does not use the material-damage arrow implementation"); + arrows++; + } + + if (isBaseMetalsItem(material, Names.BOLT)) { + require(material.getItem(Names.BOLT) instanceof ItemBaseMetalsBolt, + material.getItem(Names.BOLT).getRegistryName() + + " does not use the material-damage bolt implementation"); + bolts++; + } + + if (isBaseMetalsItem(material, Names.BOW)) { + require(material.getItem(Names.BOW) instanceof ItemBaseMetalsBow, + material.getItem(Names.BOW).getRegistryName() + + " does not use the material-damage bow implementation"); + bows++; + } + } + + require(arrows == 27, "Checked " + arrows + " Base Metals arrows, expected 27"); + require(bolts == 27, "Checked " + bolts + " Base Metals bolts, expected 27"); + require(bows == 27, "Checked " + bows + " Base Metals bows, expected 27"); + + return arrows + bolts + bows; + } + + private static boolean isBaseMetalsItem(final MMDMaterial material, final Names name) { + if (!material.hasItem(name)) { + return false; + } + + final ResourceLocation registryName = material.getItem(name).getRegistryName(); + + return registryName != null && "basemetals".equals(registryName.getNamespace()); + } + + private static int verifyRangedDamage(final MinecraftServer server) { + final WorldServer world = server.getWorld(0); + final EntityPlayerMP shooter = new EntityPlayerMP(server, world, + new GameProfile(UUID.randomUUID(), "BaseMetalsDamageProbe"), + new PlayerInteractionManager(world)); + final BlockPos spawn = world.getSpawnPoint(); + + shooter.setPositionAndRotation(spawn.getX() + 0.5D, spawn.getY() + 16.0D, + spawn.getZ() + 0.5D, 0.0F, 0.0F); + + int checked = 0; + + for (final MMDMaterial material : Materials.getAllMaterials()) { + if (!isBaseMetalsItem(material, Names.ARROW) + || !isBaseMetalsItem(material, Names.BOLT) + || !isBaseMetalsItem(material, Names.BOW) + || !isBaseMetalsItem(material, Names.CROSSBOW)) { + continue; + } + + final double component = material.getBaseAttackDamage(); + + requireDamage(1.0D + component, createArrowDamage(world, shooter, material), + material.getName() + " arrow ammunition"); + requireDamage(1.0D + component, createBoltDamage(world, shooter, material), + material.getName() + " bolt ammunition"); + requireDamage(component + component, + fireBowDamage(world, shooter, material.getItem(Names.BOW), + material.getItem(Names.ARROW), 0), + material.getName() + " matching bow and arrow"); + requireDamage(component + component, + fireCrossbowDamage(world, shooter, material.getItem(Names.CROSSBOW), + material.getItem(Names.BOLT), 0), + material.getName() + " matching crossbow and bolt"); + checked += 4; + } + + require(checked == 108, "Checked " + checked + " ranged material combinations, expected 108"); + + final MMDMaterial gold = Materials.getMaterialByName(MaterialNames.GOLD); + final MMDMaterial iron = Materials.getMaterialByName(MaterialNames.IRON); + final MMDMaterial adamantine = Materials.getMaterialByName(MaterialNames.ADAMANTINE); + final MMDMaterial steel = Materials.getMaterialByName(MaterialNames.STEEL); + + require(createArrowDamage(world, shooter, gold) < createArrowDamage(world, shooter, iron) + && createArrowDamage(world, shooter, iron) < createArrowDamage(world, shooter, adamantine), + "Gold, iron, and Adamantine arrows do not have increasing material damage"); + require(createBoltDamage(world, shooter, gold) < createBoltDamage(world, shooter, iron) + && createBoltDamage(world, shooter, iron) < createBoltDamage(world, shooter, adamantine), + "Gold, iron, and Adamantine bolts do not have increasing material damage"); + + requireDamage(2.0D, + fireBowDamage(world, shooter, net.minecraft.init.Items.BOW, + net.minecraft.init.Items.ARROW, 0), + "vanilla bow and arrow"); + checked++; + requireDamage(1.0D + adamantine.getBaseAttackDamage(), + fireBowDamage(world, shooter, net.minecraft.init.Items.BOW, + adamantine.getItem(Names.ARROW), 0), + "vanilla bow and Adamantine arrow"); + checked++; + requireDamage(1.0D + adamantine.getBaseAttackDamage(), + fireBowDamage(world, shooter, adamantine.getItem(Names.BOW), + net.minecraft.init.Items.ARROW, 0), + "Adamantine bow and vanilla arrow"); + checked++; + + final double goldBowAdamantineArrow = fireBowDamage(world, shooter, + gold.getItem(Names.BOW), adamantine.getItem(Names.ARROW), 0); + final double adamantineBowGoldArrow = fireBowDamage(world, shooter, + adamantine.getItem(Names.BOW), gold.getItem(Names.ARROW), 0); + + requireDamage(gold.getBaseAttackDamage() + adamantine.getBaseAttackDamage(), + goldBowAdamantineArrow, "gold bow and Adamantine arrow"); + requireDamage(goldBowAdamantineArrow, adamantineBowGoldArrow, + "swapped bow and arrow materials"); + checked += 2; + + final double goldCrossbowAdamantineBolt = fireCrossbowDamage(world, shooter, + gold.getItem(Names.CROSSBOW), adamantine.getItem(Names.BOLT), 0); + final double adamantineCrossbowGoldBolt = fireCrossbowDamage(world, shooter, + adamantine.getItem(Names.CROSSBOW), gold.getItem(Names.BOLT), 0); + + requireDamage(gold.getBaseAttackDamage() + adamantine.getBaseAttackDamage(), + goldCrossbowAdamantineBolt, "gold crossbow and Adamantine bolt"); + requireDamage(goldCrossbowAdamantineBolt, adamantineCrossbowGoldBolt, + "swapped crossbow and bolt materials"); + checked += 2; + + final int powerLevel = 2; + final double powerBonus = powerLevel * 0.5D + 0.5D; + + requireDamage(steel.getBaseAttackDamage() * 2.0D + powerBonus, + fireBowDamage(world, shooter, steel.getItem(Names.BOW), + steel.getItem(Names.ARROW), powerLevel), + "Power-enchanted steel bow and arrow"); + requireDamage(steel.getBaseAttackDamage() * 2.0D + powerBonus, + fireCrossbowDamage(world, shooter, steel.getItem(Names.CROSSBOW), + steel.getItem(Names.BOLT), powerLevel), + "Power-enchanted steel crossbow and bolt"); + checked += 2; + + final ItemBolt neutralBolt = new ItemBolt(); + + requireDamage(1.0D + adamantine.getBaseAttackDamage(), + fireCrossbowDamage(world, shooter, adamantine.getItem(Names.CROSSBOW), + neutralBolt, 0), + "Adamantine crossbow and neutral third-party bolt"); + checked++; + + final ItemArrow thirdPartyArrow = new ItemArrow() { + @Override + public EntityArrow createArrow(final World arrowWorld, final ItemStack stack, + final net.minecraft.entity.EntityLivingBase arrowShooter) { + final EntityArrow projectile = super.createArrow(arrowWorld, stack, arrowShooter); + + projectile.setDamage(4.25D); + + return projectile; + } + }; + + requireDamage(4.25D - 1.0D + adamantine.getBaseAttackDamage(), + fireBowDamage(world, shooter, adamantine.getItem(Names.BOW), + thirdPartyArrow, 0), + "Adamantine bow and third-party arrow"); + checked++; + require(checked == 119, "Checked " + checked + " ranged damage cases, expected 119"); + + return checked; + } + + private static double fireBowDamage(final World world, final EntityPlayer shooter, + final Item bow, final Item arrow, final int powerLevel) { + final ItemStack bowStack = new ItemStack(bow); + + if (powerLevel > 0) { + bowStack.addEnchantment(Enchantments.POWER, powerLevel); + } + + final ItemStack ammunition = new ItemStack(arrow, 2); + + shooter.setHeldItem(EnumHand.OFF_HAND, ammunition); + + final int before = countArrows(world); + EntityArrow projectile = null; + + try { + bow.onPlayerStoppedUsing(bowStack, world, shooter, + bow.getMaxItemUseDuration(bowStack) - 20); + require(countArrows(world) == before + 1, + bow.getRegistryName() + " did not create a server-side arrow"); + projectile = findLiveArrow(world); + require(projectile != null, "Spawned arrow could not be located"); + require(ammunition.getCount() == 1, + bow.getRegistryName() + " consumed an unexpected number of arrows"); + require(bowStack.getItemDamage() == 1, + bow.getRegistryName() + " did not lose one durability after firing"); + + return projectile.getDamage(); + } finally { + if (projectile != null) { + projectile.setDead(); + } + + shooter.setHeldItem(EnumHand.OFF_HAND, ItemStack.EMPTY); + } + } + + private static double fireCrossbowDamage(final World world, final EntityPlayer shooter, + final Item crossbow, final Item bolt, final int powerLevel) { + final ItemStack crossbowStack = new ItemStack(crossbow); + + if (powerLevel > 0) { + crossbowStack.addEnchantment(Enchantments.POWER, powerLevel); + } + + final ItemStack ammunition = new ItemStack(bolt, 2); + + shooter.setHeldItem(EnumHand.OFF_HAND, ammunition); + + final int before = countBolts(world); + EntityCustomBolt projectile = null; + + try { + crossbow.onPlayerStoppedUsing(crossbowStack, world, shooter, + crossbow.getMaxItemUseDuration(crossbowStack) - 20); + require(countBolts(world) == before + 1, + crossbow.getRegistryName() + " did not create a server-side bolt"); + projectile = findLiveBolt(world); + require(projectile != null, "Spawned bolt could not be located"); + require(ammunition.getCount() == 1, + crossbow.getRegistryName() + " consumed an unexpected number of bolts"); + require(crossbowStack.getItemDamage() == 1, + crossbow.getRegistryName() + " did not lose one durability after firing"); + + return projectile.getDamage(); + } finally { + if (projectile != null) { + projectile.setDead(); + } + + shooter.setHeldItem(EnumHand.OFF_HAND, ItemStack.EMPTY); + } + } + + private static int countArrows(final World world) { + int count = 0; + + for (final Entity entity : world.loadedEntityList) { + if (entity instanceof EntityArrow && !(entity instanceof EntityCustomBolt) + && !entity.isDead) { + count++; + } + } + + return count; + } + + private static EntityArrow findLiveArrow(final World world) { + for (final Entity entity : world.loadedEntityList) { + if (entity instanceof EntityArrow && !(entity instanceof EntityCustomBolt) + && !entity.isDead) { + return (EntityArrow) entity; + } + } + + return null; + } + + private static void requireDamage(final double expected, final double actual, + final String description) { + require(Math.abs(expected - actual) < 0.000001D, + description + " has projectile base damage " + actual + ", expected " + expected); + } + + private static double createArrowDamage(final World world, final EntityPlayer shooter, + final MMDMaterial material) { + final Item item = material.getItem(Names.ARROW); + + require(item instanceof ItemArrow, + material.getName() + " arrow is not an ItemArrow"); + + final EntityArrow projectile = ((ItemArrow) item).createArrow( + world, new ItemStack(item), shooter); + final double damage = projectile.getDamage(); + + projectile.setDead(); + + return damage; + } + + private static double createBoltDamage(final World world, final EntityPlayer shooter, + final MMDMaterial material) { + final Item item = material.getItem(Names.BOLT); + + require(item instanceof ItemBolt, + material.getName() + " bolt is not an ItemBolt"); + + final EntityCustomBolt projectile = ((ItemBolt) item).createBolt( + world, new ItemStack(item), shooter); + final double damage = projectile.getDamage(); + + projectile.setDead(); + + return damage; + } + + private static int countBolts(final World world) { + int count = 0; + + for (final Entity entity : world.loadedEntityList) { + if (entity instanceof EntityCustomBolt && !entity.isDead) { + count++; + } + } + + return count; + } + + private static EntityCustomBolt findLiveBolt(final World world) { + for (final Entity entity : world.loadedEntityList) { + if (entity instanceof EntityCustomBolt && !entity.isDead) { + return (EntityCustomBolt) entity; + } + } + + return null; + } + + private static int verifyArmorEffects(final MinecraftServer server) { + final WorldServer world = server.getWorld(0); + int checked = 0; + + for (int pieces = 1; pieces <= 4; pieces++) { + final EntityPlayer player = armorTestPlayer(server, world, + "StarSteel" + pieces); + final ItemStack trigger = equipArmor(player, MaterialNames.STARSTEEL, pieces); + + Materials.getMaterialByName(MaterialNames.STARSTEEL).applyEffect(trigger, player); + requireEffect(player, MobEffects.JUMP_BOOST, pieces - 1, + "Star-Steel " + pieces + "-piece jump boost"); + + if (pieces == 1) { + requireNoEffect(player, MobEffects.SPEED, + "Star-Steel one-piece speed boost"); + } else { + requireEffect(player, MobEffects.SPEED, pieces - 2, + "Star-Steel " + pieces + "-piece speed boost"); + } + + checked += 2; + } + + for (int pieces = 1; pieces <= 4; pieces++) { + final EntityPlayer player = armorTestPlayer(server, world, + "Adamantine" + pieces); + final ItemStack trigger = equipArmor(player, MaterialNames.ADAMANTINE, pieces); + + Materials.getMaterialByName(MaterialNames.ADAMANTINE).applyEffect(trigger, player); + + if (pieces == 1) { + requireNoEffect(player, MobEffects.RESISTANCE, + "Adamantine one-piece resistance"); + } else { + requireEffect(player, MobEffects.RESISTANCE, pieces == 4 ? 1 : 0, + "Adamantine " + pieces + "-piece resistance"); + } + + checked++; + } + + for (int pieces = 1; pieces <= 4; pieces++) { + final EntityPlayer player = armorTestPlayer(server, world, + "Lead" + pieces); + final ItemStack trigger = equipArmor(player, MaterialNames.LEAD, pieces); + + Materials.getMaterialByName(MaterialNames.LEAD).applyEffect(trigger, player); + + if (pieces == 1) { + requireNoEffect(player, MobEffects.SLOWNESS, + "Lead one-piece slowness"); + } else { + requireEffect(player, MobEffects.SLOWNESS, pieces == 4 ? 1 : 0, + "Lead " + pieces + "-piece slowness"); + } + + checked++; + } + + final EntityPlayer coldIronPartial = armorTestPlayer(server, world, + "ColdIronPartial"); + final ItemStack coldIronPartialTrigger = equipArmor( + coldIronPartial, MaterialNames.COLDIRON, 3); + + Materials.getMaterialByName(MaterialNames.COLDIRON) + .applyEffect(coldIronPartialTrigger, coldIronPartial); + requireNoEffect(coldIronPartial, MobEffects.FIRE_RESISTANCE, + "Cold-Iron partial-suit fire resistance"); + checked++; + + final EntityPlayer coldIronFull = armorTestPlayer(server, world, + "ColdIronFull"); + final ItemStack coldIronFullTrigger = equipArmor( + coldIronFull, MaterialNames.COLDIRON, 4); + + Materials.getMaterialByName(MaterialNames.COLDIRON) + .applyEffect(coldIronFullTrigger, coldIronFull); + requireEffect(coldIronFull, MobEffects.FIRE_RESISTANCE, 0, + "Cold-Iron full-suit fire resistance"); + checked++; + + final EntityPlayer mithrilPartial = armorTestPlayer(server, world, + "MithrilPartial"); + final ItemStack mithrilPartialTrigger = equipArmor( + mithrilPartial, MaterialNames.MITHRIL, 3); + + mithrilPartial.addPotionEffect(new PotionEffect(MobEffects.POISON, 200, 0)); + Materials.getMaterialByName(MaterialNames.MITHRIL) + .applyEffect(mithrilPartialTrigger, mithrilPartial); + requireEffect(mithrilPartial, MobEffects.POISON, 0, + "Mithril partial-suit harmful-effect preservation"); + checked++; + + final EntityPlayer mithrilFull = armorTestPlayer(server, world, + "MithrilFull"); + final ItemStack mithrilFullTrigger = equipArmor( + mithrilFull, MaterialNames.MITHRIL, 4); + + mithrilFull.addPotionEffect(new PotionEffect(MobEffects.POISON, 200, 0)); + Materials.getMaterialByName(MaterialNames.MITHRIL) + .applyEffect(mithrilFullTrigger, mithrilFull); + requireNoEffect(mithrilFull, MobEffects.POISON, + "Mithril full-suit harmful-effect removal"); + checked++; + + final BlockPos waterFeet = new BlockPos(24, 80, 24); + final BlockPos waterHead = waterFeet.up(); + final net.minecraft.block.state.IBlockState originalFeet = world.getBlockState(waterFeet); + final net.minecraft.block.state.IBlockState originalHead = world.getBlockState(waterHead); + + try { + world.setBlockState(waterFeet, Blocks.FLOWING_WATER.getDefaultState(), 2); + world.setBlockState(waterHead, Blocks.FLOWING_WATER.getDefaultState(), 2); + + final EntityPlayer aquariumPartial = armorTestPlayer(server, world, + "AquariumPartial"); + + aquariumPartial.setPosition(24.5D, 80.0D, 24.5D); + aquariumPartial.handleWaterMovement(); + + final ItemStack aquariumPartialTrigger = equipArmor( + aquariumPartial, MaterialNames.AQUARIUM, 3); + + Materials.getMaterialByName(MaterialNames.AQUARIUM) + .applyEffect(aquariumPartialTrigger, aquariumPartial); + requireNoEffect(aquariumPartial, MobEffects.WATER_BREATHING, + "Aquarium partial-suit water breathing"); + checked++; + + final EntityPlayer aquariumFull = armorTestPlayer(server, world, + "AquariumFull"); + + aquariumFull.setPosition(24.5D, 80.0D, 24.5D); + aquariumFull.handleWaterMovement(); + + final ItemStack aquariumFullTrigger = equipArmor( + aquariumFull, MaterialNames.AQUARIUM, 4); + + aquariumFull.addPotionEffect(new PotionEffect(MobEffects.MINING_FATIGUE, 200, 0)); + Materials.getMaterialByName(MaterialNames.AQUARIUM) + .applyEffect(aquariumFullTrigger, aquariumFull); + requireEffect(aquariumFull, MobEffects.WATER_BREATHING, 0, + "Aquarium full-suit water breathing"); + requireEffect(aquariumFull, MobEffects.RESISTANCE, 0, + "Aquarium full-suit resistance"); + requireNoEffect(aquariumFull, MobEffects.MINING_FATIGUE, + "Aquarium full-suit mining-fatigue removal"); + checked += 3; + } finally { + world.setBlockState(waterFeet, originalFeet, 2); + world.setBlockState(waterHead, originalHead, 2); + } + + final EntityPlayer aquariumDry = armorTestPlayer(server, world, + "AquariumDry"); + + aquariumDry.setPosition(24.5D, 82.0D, 24.5D); + + final ItemStack aquariumDryTrigger = equipArmor( + aquariumDry, MaterialNames.AQUARIUM, 4); + + Materials.getMaterialByName(MaterialNames.AQUARIUM) + .applyEffect(aquariumDryTrigger, aquariumDry); + requireNoEffect(aquariumDry, MobEffects.WATER_BREATHING, + "Aquarium dry full-suit water breathing"); + checked++; + + require(!new ColdIronProperty().hasEffect( + new ItemStack(net.minecraft.init.Items.DIAMOND), coldIronFull), + "Cold-Iron property accepts an unrelated item"); + checked++; + + final EntityPlayer starSteelContract = armorTestPlayer(server, world, + "StarSteelContract"); + final ItemStack starSteelContractTrigger = equipArmor( + starSteelContract, MaterialNames.STARSTEEL, 1); + + require(new StarSteelProperty().hasEffect( + starSteelContractTrigger, starSteelContract), + "Star-Steel property rejected its own equipped armor"); + checked++; + + final EntityPlayer starSteelTickPlayer = armorTestPlayer(server, world, + "StarSteelArmorTick"); + final ItemStack starSteelTickTrigger = equipArmor( + starSteelTickPlayer, MaterialNames.STARSTEEL, 4); + + if (world.getTotalWorldTime() == 0L) { + world.getWorldInfo().setWorldTotalTime(1L); + } + + starSteelTickTrigger.getItem().onArmorTick( + world, starSteelTickPlayer, starSteelTickTrigger); + starSteelTickTrigger.getItem().onArmorTick( + world, starSteelTickPlayer, starSteelTickTrigger); + requireEffect(starSteelTickPlayer, MobEffects.JUMP_BOOST, 3, + "Star-Steel armor-tick jump boost"); + requireEffect(starSteelTickPlayer, MobEffects.SPEED, 2, + "Star-Steel armor-tick speed boost"); + checked += 2; + + final BlockPos tickWaterFeet = new BlockPos(28, 80, 28); + final BlockPos tickWaterHead = tickWaterFeet.up(); + final net.minecraft.block.state.IBlockState originalTickFeet = world.getBlockState(tickWaterFeet); + final net.minecraft.block.state.IBlockState originalTickHead = world.getBlockState(tickWaterHead); + + try { + world.setBlockState(tickWaterFeet, Blocks.WATER.getDefaultState(), 2); + world.setBlockState(tickWaterHead, Blocks.WATER.getDefaultState(), 2); + + final EntityPlayer aquariumTickPlayer = armorTestPlayer(server, world, + "AquariumArmorTick"); + + aquariumTickPlayer.setPosition(28.5D, 80.0D, 28.5D); + aquariumTickPlayer.handleWaterMovement(); + + final ItemStack aquariumTickTrigger = equipArmor( + aquariumTickPlayer, MaterialNames.AQUARIUM, 4); + + aquariumTickTrigger.getItem().onArmorTick( + world, aquariumTickPlayer, aquariumTickTrigger); + aquariumTickTrigger.getItem().onArmorTick( + world, aquariumTickPlayer, aquariumTickTrigger); + requireEffect(aquariumTickPlayer, MobEffects.WATER_BREATHING, 0, + "Aquarium armor-tick water breathing"); + requireEffect(aquariumTickPlayer, MobEffects.RESISTANCE, 0, + "Aquarium armor-tick resistance"); + checked += 2; + } finally { + world.setBlockState(tickWaterFeet, originalTickFeet, 2); + world.setBlockState(tickWaterHead, originalTickHead, 2); + } + + return checked; + } + + private static EntityPlayer armorTestPlayer( + final MinecraftServer server, + final WorldServer world, + final String name) { + return new ProbePlayer(world, + new GameProfile(UUID.nameUUIDFromBytes(name.getBytes()), name)); + } + + private static ItemStack equipArmor( + final EntityPlayer player, + final String materialName, + final int pieces) { + final MMDMaterial material = Materials.getMaterialByName(materialName); + final EntityEquipmentSlot[] slots = { + EntityEquipmentSlot.FEET, + EntityEquipmentSlot.LEGS, + EntityEquipmentSlot.CHEST, + EntityEquipmentSlot.HEAD + }; + final Names[] forms = { + Names.BOOTS, + Names.LEGGINGS, + Names.CHESTPLATE, + Names.HELMET + }; + ItemStack trigger = ItemStack.EMPTY; + + for (int i = 0; i < pieces; i++) { + final ItemStack armor = new ItemStack(material.getItem(forms[i])); + + player.setItemStackToSlot(slots[i], armor); + + if (trigger.isEmpty()) { + trigger = armor; + } + } + + return trigger; + } + + private static void requireEffect( + final EntityPlayer player, + final net.minecraft.potion.Potion potion, + final int amplifier, + final String description) { + final PotionEffect effect = player.getActivePotionEffect(potion); + + require(effect != null, description + " was not applied"); + require(effect.getAmplifier() == amplifier, + description + " has amplifier " + effect.getAmplifier() + + ", expected " + amplifier); + } + + private static void requireNoEffect( + final EntityPlayer player, + final net.minecraft.potion.Potion potion, + final String description) { + require(player.getActivePotionEffect(potion) == null, + description + " was unexpectedly applied"); + } + + private static final class ProbePlayer extends EntityPlayer { + private ProbePlayer(final World world, final GameProfile profile) { + super(world, profile); + } + + @Override + public boolean isSpectator() { + return false; + } + + @Override + public boolean isCreative() { + return false; + } + } + + private static void verifyRailRecipe( + final World world, + final String recipePath, + final Item expectedItem, + final int expectedCount, + final Item... grid) { + require(grid.length == 9, "Rail recipe test grid must contain nine slots"); + + final InventoryCrafting crafting = new InventoryCrafting(new Container() { + @Override + public boolean canInteractWith(final EntityPlayer playerIn) { + return false; + } + }, 3, 3); + + for (int slot = 0; slot < grid.length; slot++) { + if (grid[slot] != null) { + crafting.setInventorySlotContents(slot, new ItemStack(grid[slot])); + } + } + + final ResourceLocation expectedRecipe = new ResourceLocation("basemetals", recipePath); + final IRecipe registeredRecipe = CraftingManager.REGISTRY.getObject(expectedRecipe); + + require(registeredRecipe != null, "Crafting recipe was not registered: " + expectedRecipe); + require(registeredRecipe.matches(crafting, world), + "Registered crafting recipe did not match its canonical input: " + expectedRecipe); + + final IRecipe recipe = CraftingManager.findMatchingRecipe(crafting, world); + + require(recipe != null, "No crafting recipe matched " + expectedRecipe); + require(expectedRecipe.equals(recipe.getRegistryName()), + "Crafting input for " + expectedRecipe + " matched " + recipe.getRegistryName()); + + final ItemStack result = recipe.getCraftingResult(crafting); + + require(!result.isEmpty(), "Crafting recipe " + expectedRecipe + " returned an empty result"); + require(result.getItem() == expectedItem, + "Crafting recipe " + expectedRecipe + " returned " + result.getItem().getRegistryName() + + ", expected " + expectedItem.getRegistryName()); + require(result.getCount() == expectedCount, + "Crafting recipe " + expectedRecipe + " returned " + result.getCount() + + " items, expected " + expectedCount); + } + + private static int verifyDoorAndTrapdoorRecipe( + final World world, + final Item ingredient, + final String material) { + requireCreativeRegistryEntry(material + "_door"); + requireCreativeRegistryEntry(material + "_trapdoor"); + verifyCraftingResult(world, ingredient, material + "_door", 3, 2, 3); + + if ("quartz".equals(material)) { + verifyCraftingResult(world, Item.getItemFromBlock(Blocks.QUARTZ_BLOCK), + material + "_trapdoor", 1, 1, 1); + } else { + verifyCraftingResult(world, ingredient, material + "_trapdoor", 1, 2, 2); + } + + return 2; + } + + private static void requireCreativeRegistryEntry(final String path) { + final ResourceLocation registryName = new ResourceLocation("basemetals", path); + final Block block = Block.REGISTRY.getObject(registryName); + + require(block != null && registryName.equals(block.getRegistryName()), + "Missing registered block " + registryName); + + final Item item = Item.REGISTRY.getObject(registryName); + + require(item != null && registryName.equals(item.getRegistryName()), + "Missing registered item " + registryName); + require(item.getCreativeTab() != null, + "Registered item is absent from creative tabs: " + registryName); + } + + private static void verifyCraftingResult( + final World world, + final Item ingredient, + final String expectedPath, + final int expectedCount, + final int width, + final int height) { + final InventoryCrafting crafting = new InventoryCrafting(new Container() { + @Override + public boolean canInteractWith(final EntityPlayer playerIn) { + return false; + } + }, 3, 3); + + for (int row = 0; row < height; row++) { + for (int column = 0; column < width; column++) { + crafting.setInventorySlotContents(column + row * 3, new ItemStack(ingredient)); + } + } + + final ResourceLocation expectedRecipe = new ResourceLocation("basemetals", expectedPath); + final IRecipe registeredRecipe = CraftingManager.REGISTRY.getObject(expectedRecipe); + + require(registeredRecipe != null, "Crafting recipe was not registered: " + expectedRecipe); + require(registeredRecipe.matches(crafting, world), + "Registered crafting recipe did not match its canonical input: " + expectedRecipe); + + final IRecipe recipe = CraftingManager.findMatchingRecipe(crafting, world); + + require(recipe != null, "No crafting recipe matched " + expectedRecipe); + require(expectedRecipe.equals(recipe.getRegistryName()), + "Crafting input for " + expectedRecipe + " matched " + recipe.getRegistryName()); + + final ItemStack result = recipe.getCraftingResult(crafting); + + require(!result.isEmpty(), "Crafting recipe " + expectedRecipe + " returned an empty result"); + require(expectedRecipe.equals(result.getItem().getRegistryName()), + "Crafting recipe " + expectedRecipe + " returned " + result.getItem().getRegistryName()); + require(result.getCount() == expectedCount, + "Crafting recipe " + expectedRecipe + " returned " + result.getCount() + + " items, expected " + expectedCount); + } + + private static String requiredProperty(final String name) { + final String value = System.getProperty(name); + + if (value == null || value.trim().isEmpty()) { + throw new IllegalStateException("Missing system property " + name); + } + + return value; + } + + private static String version(final String modid) { + for (final ModContainer mod : Loader.instance().getModList()) { + if (modid.equals(mod.getModId())) { + return mod.getVersion(); + } + } + + throw new IllegalStateException("Missing loaded mod " + modid); + } + + private static Item requireItem(final String namespace, final String path) { + final ResourceLocation registryName = new ResourceLocation(namespace, path); + final Item item = Item.REGISTRY.getObject(registryName); + + require(item != null && registryName.equals(item.getRegistryName()), + "Missing registered item " + registryName); + + return item; + } + + private static void requireRegistered(final Object value, final String registryName) { + require(value != null, "Missing registry object " + registryName); + } + + private static void require(final boolean condition, final String message) { + if (!condition) { + throw new IllegalStateException(message); + } + } } diff --git a/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsTinkersRuntimeProbe.java b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsTinkersRuntimeProbe.java index 5cfdca33..746ad5fd 100644 --- a/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsTinkersRuntimeProbe.java +++ b/src/test/java/com/mcmoddev/basemetals/test/BaseMetalsTinkersRuntimeProbe.java @@ -12,6 +12,9 @@ import com.mcmoddev.basemetals.content.ContentMode; import com.mcmoddev.basemetals.util.BMeConfig; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.InventoryCrafting; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.CraftingManager; @@ -32,315 +35,372 @@ import slimeknights.tconstruct.library.smeltery.AlloyRecipe; import slimeknights.tconstruct.library.smeltery.MeltingRecipe; -/** Test-only Tinkers/TAIGA compatibility probe. This class never enters the public jar. */ +/** Checks material registration with Tinkers alone and with TAIGA installed. */ @Mod( - modid = BaseMetalsTinkersRuntimeProbe.MODID, - name = "Base Metals Tinkers Runtime Probe", - version = "1", - dependencies = "required-after:basemetals;required-after:mmdlib;required-after:orespawn;" - + "required-after:mantle;required-after:tconstruct", - acceptedMinecraftVersions = "[1.12.2]") + modid = BaseMetalsTinkersRuntimeProbe.MODID, + name = "Base Metals Tinkers Runtime Probe", + version = "1", + dependencies = "required-after:basemetals;required-after:mmdlib;required-after:orespawn;" + + "required-after:mantle;required-after:tconstruct", + acceptedMinecraftVersions = "[1.12.2]") public final class BaseMetalsTinkersRuntimeProbe { - public static final String MODID = "basemetals_tinkers_runtime_probe"; - - // The published TAIGA 1.3.4 jar retains 1.3.3 in its embedded mod metadata. - private static final String TAIGA_EMBEDDED_VERSION = "1.12.2-1.3.3"; - - private static final List ADAMANT_FORMS = Arrays.asList( - "oreAdamant", "blockAdamant", "plateAdamant", "doorAdamant", - "nuggetAdamant", "trapdoorAdamant", "dustAdamant", "gearAdamant", - "rodAdamant", "barsAdamant", "ingotAdamant", "dustTinyAdamant", - "dustSmallAdamant"); - - @EventHandler - public void serverStarted(final FMLServerStartedEvent event) throws IOException { - final boolean expectedTaiga = Boolean.parseBoolean( - requiredProperty("basemetals.probe.expectedTaiga")); - final boolean expectedPrismarine = Boolean.parseBoolean( - requiredProperty("basemetals.probe.expectedPrismarine")); - final boolean expectedConArm = Boolean.parseBoolean( - requiredProperty("basemetals.probe.expectedConArm")); - final ContentMode expectedContentMode = ContentMode.fromSerializedName( - requiredProperty("basemetals.probe.expectedContentMode")); - final File marker = new File(requiredProperty("basemetals.probe.marker")); - final Properties result = new Properties(); - - require(Loader.isModLoaded("basemetals"), "Base Metals did not load"); - require(Loader.isModLoaded("mmdlib"), "MMDLib did not load"); - require(Loader.isModLoaded("orespawn"), "OreSpawn did not load"); - require(Loader.isModLoaded("mantle"), "Mantle did not load"); - require(Loader.isModLoaded("tconstruct"), "Tinkers Construct did not load"); - require(BMeConfig.getActiveContentMode() == expectedContentMode, - "Content mode did not match expected mode " + expectedContentMode - + "; actual=" + BMeConfig.getActiveContentMode()); - require(Loader.isModLoaded("taiga") == expectedTaiga, - "TAIGA loaded state did not match expected state " + expectedTaiga); - require(Loader.isModLoaded("conarm") == expectedConArm, - "Construct's Armory loaded state did not match expected state " + expectedConArm); - verifyPrismarineConfiguration(expectedPrismarine); - verifyCoreContentPolicy(expectedContentMode); - - final Item adamantineIngot = requireItem("basemetals", "adamantine_ingot"); - verifyBaseAliases("Adamantine"); - verifyBaseAliases("Adamantite"); - verifyBaseAliases("Adamantium"); - - final Fluid adamantineFluid = requireFluid("adamantine"); - if (expectedContentMode == ContentMode.REALISM) { - require(meltingFluids(adamantineIngot).isEmpty(), - "Realism exposes Adamantine Tinkers melting outputs: " - + meltingFluids(adamantineIngot)); - } else { - require(meltingFluids(adamantineIngot).equals(singleton(adamantineFluid.getName())), - "Base Metals Adamantine ingot has ambiguous Tinkers melting outputs: " - + meltingFluids(adamantineIngot)); - } - verifyMaterialStats(expectedContentMode); - verifyArmorMaterialStats(expectedContentMode, expectedConArm); - - if (expectedTaiga) { - require(TAIGA_EMBEDDED_VERSION.equals(version("taiga")), - "Unexpected TAIGA version " + version("taiga")); - verifyNoBaseMetalsAdamantAliases(); - verifyTaigaAliases(); - - final Item taigaAdamantIngot = requireItem("taiga", "adamant_ingot"); - final Fluid taigaAdamantFluid = requireFluid("adamant_fluid"); - require(adamantineFluid != taigaAdamantFluid, - "Base Metals Adamantine and TAIGA Adamant share one fluid instance"); - require(meltingFluids(taigaAdamantIngot).equals(singleton(taigaAdamantFluid.getName())), - "TAIGA Adamant ingot has ambiguous Tinkers melting outputs: " - + meltingFluids(taigaAdamantIngot)); - } else { - verifyBaseAliases("Adamant"); - require(FluidRegistry.getFluid("adamant_fluid") == null, - "TAIGA Adamant fluid exists when TAIGA is absent"); - } - - result.setProperty("phase", System.getProperty("basemetals.probe.phase", "unknown")); - result.setProperty("taiga", Boolean.toString(expectedTaiga)); - result.setProperty("conarm", Boolean.toString(expectedConArm)); - result.setProperty("prismarine", Boolean.toString(expectedPrismarine)); - result.setProperty("contentMode", expectedContentMode.serializedName()); - if (expectedTaiga) { - result.setProperty("taigaEmbeddedVersion", version("taiga")); - } - result.setProperty("adamantineMeltingOutputs", - meltingFluids(adamantineIngot).toString()); - result.setProperty("registered", "true"); - marker.getParentFile().mkdirs(); - try (FileOutputStream output = new FileOutputStream(marker)) { - result.store(output, "Base Metals Tinkers/TAIGA qualification"); - } - FMLCommonHandler.instance().getMinecraftServerInstance().initiateShutdown(); - } - - private static void verifyArmorMaterialStats(final ContentMode mode, - final boolean expectedConArm) { - if (!expectedConArm) { - return; - } - final String allowed = mode == ContentMode.REALISM ? "nickel" : "adamantine"; - requireStats(allowed, allowed, "core", "plates", "trim"); - if (mode != ContentMode.HIGH_FANTASY) { - // Use a Base Metals-specific material here. Tinkers itself owns a - // pre-existing Lead material and its third-party stats remain - // authoritative even when Base Metals recipes are restricted. - final Material bismuth = TinkerRegistry.getMaterial("bismuth"); - require(bismuth != Material.UNKNOWN, - "Missing restricted-mode Tinkers material Bismuth"); - require(!bismuth.hasStats("core") && !bismuth.hasStats("plates") - && !bismuth.hasStats("trim"), - "Restricted mode exposed Bismuth Construct's Armory stats"); - } - } - - private static void verifyCoreContentPolicy(final ContentMode mode) { - // Registry identities and creative recovery remain stable in every mode. - for (final String path : Arrays.asList("adamantine_bow", "adamantine_pickaxe", - "pewter_chestplate", "bronze_pickaxe", "mercury_ingot")) { - final Item item = requireItem("basemetals", path); - require(item.getCreativeTab() != null, - "Restricted item is unavailable for creative recovery: " + path); - } - - final boolean high = mode == ContentMode.HIGH_FANTASY; - final boolean realism = mode == ContentMode.REALISM; - verifyRecipeOutput("adamantine_bow", high); - verifyRecipeOutput("adamantine_pickaxe", !realism); - verifyRecipeOutput("pewter_chestplate", high); - verifyRecipeOutput("bronze_pickaxe", true); - - final ItemStack adamantinePowder = new ItemStack( - requireItem("basemetals", "adamantine_powder")); - final ItemStack adamantineIngot = new ItemStack( - requireItem("basemetals", "adamantine_ingot")); - final ItemStack smelted = FurnaceRecipes.instance().getSmeltingResult(adamantinePowder); - require(smelted.isEmpty() == realism, - "Adamantine furnace acquisition does not match " + mode + ": " + smelted); - require((CrusherRecipeRegistry.getRecipeForInputItem(adamantineIngot) == null) == realism, - "Adamantine crusher acquisition does not match " + mode); - - final ItemStack mercuryPowder = new ItemStack( - requireItem("basemetals", "mercury_powder")); - final ItemStack mercurySmelted = FurnaceRecipes.instance().getSmeltingResult(mercuryPowder); - require(mercurySmelted.isEmpty() == realism, - "Mercury reagent ingot acquisition does not match " + mode + ": " - + mercurySmelted); - } - - private static void verifyRecipeOutput(final String path, final boolean expectedAllowed) { - final ResourceLocation id = new ResourceLocation("basemetals", path); - final IRecipe recipe = CraftingManager.REGISTRY.getObject(id); - require(recipe != null, "Missing stable recipe identity " + id); - require(!recipe.getRecipeOutput().isEmpty() == expectedAllowed, - "Recipe policy for " + id + " does not match expected allowed=" - + expectedAllowed + "; output=" + recipe.getRecipeOutput()); - require(recipe.isDynamic() != expectedAllowed, - "Recipe-book visibility for " + id + " does not match expected allowed=" - + expectedAllowed); - } - - private static void verifyMaterialStats(final ContentMode mode) { - if (mode == ContentMode.REALISM) { - require(TinkerRegistry.getMaterial("adamantine") == Material.UNKNOWN, - "Realism exposed mythical Adamantine as a Tinkers material"); - verifyRestrictedStats("nickel", "Nickel"); - return; - } - - if (mode == ContentMode.HIGH_FANTASY) { - requireStats("adamantine", "Adamantine", "head", "handle", "extra", "bow", - "bowstring", "shaft", "fletching"); - } else { - verifyRestrictedStats("adamantine", "Adamantine"); - } - } - - private static void verifyRestrictedStats(final String identifier, final String displayName) { - final Material material = TinkerRegistry.getMaterial(identifier); - require(material != Material.UNKNOWN, "Missing Tinkers material " + identifier); - requireStats(identifier, displayName, "head", "handle", "extra", "shaft", "fletching"); - require(!material.hasStats("bow"), displayName + " exposes restricted bow stats"); - require(!material.hasStats("bowstring"), - displayName + " exposes restricted bowstring stats"); - } - - private static void requireStats(final String materialIdentifier, final String displayName, - final String... identifiers) { - final Material material = TinkerRegistry.getMaterial(materialIdentifier); - require(material != Material.UNKNOWN, "Missing Tinkers material " + materialIdentifier); - for (final String identifier : identifiers) { - require(material.hasStats(identifier), - displayName + " is missing Tinkers stats " + identifier); - } - } - - private static void verifyPrismarineConfiguration(final boolean expectedPrismarine) { - final Fluid prismarine = FluidRegistry.getFluid("prismarine"); - if (expectedPrismarine) { - require(prismarine != null, "Prismarine fluid is missing when enabled"); - return; - } - - require(prismarine == null, "Prismarine fluid exists when Prismarine additions are disabled"); - for (final AlloyRecipe recipe : TinkerRegistry.getAlloys()) { - if (recipe.getResult() != null && recipe.getResult().getFluid() != null) { - require(!"aquarium".equals(recipe.getResult().getFluid().getName()), - "Aquarium alloy was registered without molten Prismarine"); - } - } - } - - private static void verifyBaseAliases(final String suffix) { - requireOreEntry("ingot" + suffix, "basemetals", "adamantine_ingot"); - requireOreEntry("dust" + suffix, "basemetals", "adamantine_powder"); - requireOreEntry("nugget" + suffix, "basemetals", "adamantine_nugget"); - requireOreEntry("block" + suffix, "basemetals", "adamantine_block"); - } - - private static void verifyNoBaseMetalsAdamantAliases() { - for (final String oreName : ADAMANT_FORMS) { - for (final ItemStack stack : OreDictionary.getOres(oreName, false)) { - final ResourceLocation registryName = stack.getItem().getRegistryName(); - require(registryName == null || !"basemetals".equals(registryName.getNamespace()), - "TAIGA-owned Ore Dictionary name " + oreName - + " contains Base Metals item " + registryName); - } - } - } - - private static void verifyTaigaAliases() { - requireOreEntry("ingotAdamant", "taiga", "adamant_ingot"); - requireOreEntry("dustAdamant", "taiga", "adamant_dust"); - requireOreEntry("nuggetAdamant", "taiga", "adamant_nugget"); - requireOreEntry("blockAdamant", "taiga", "adamant_block"); - } - - private static void requireOreEntry( - final String oreName, - final String namespace, - final String path) { - final ResourceLocation expected = new ResourceLocation(namespace, path); - final List actual = new ArrayList<>(); - boolean found = false; - for (final ItemStack stack : OreDictionary.getOres(oreName, false)) { - final ResourceLocation registryName = stack.getItem().getRegistryName(); - actual.add(registryName); - if (expected.equals(registryName)) { - found = true; - } - } - require(found, "Ore Dictionary name " + oreName + " is missing " + expected - + "; entries=" + actual); - } - - private static Set meltingFluids(final Item item) { - final ItemStack stack = new ItemStack(item); - final Set fluids = new LinkedHashSet<>(); - for (final MeltingRecipe recipe : TinkerRegistry.getAllMeltingRecipies()) { - if (recipe.matches(stack)) { - fluids.add(recipe.getResult().getFluid().getName()); - } - } - return fluids; - } - - private static Set singleton(final String value) { - final Set values = new LinkedHashSet<>(); - values.add(value); - return values; - } - - private static Item requireItem(final String namespace, final String path) { - final ResourceLocation registryName = new ResourceLocation(namespace, path); - final Item item = Item.REGISTRY.getObject(registryName); - require(item != null && registryName.equals(item.getRegistryName()), - "Missing item " + registryName); - return item; - } - - private static Fluid requireFluid(final String name) { - final Fluid fluid = FluidRegistry.getFluid(name); - require(fluid != null, "Missing fluid " + name); - return fluid; - } - - private static String version(final String modid) { - return Loader.instance().getIndexedModList().get(modid).getVersion(); - } - - private static String requiredProperty(final String name) { - final String value = System.getProperty(name); - if (value == null || value.trim().isEmpty()) { - throw new IllegalStateException("Missing system property " + name); - } - return value; - } - - private static void require(final boolean condition, final String message) { - if (!condition) { - throw new IllegalStateException(message); - } - } + public static final String MODID = "basemetals_tinkers_runtime_probe"; + + // The published TAIGA 1.3.4 jar retains 1.3.3 in its embedded mod metadata. + private static final String TAIGA_EMBEDDED_VERSION = "1.12.2-1.3.3"; + + private static final List ADAMANT_FORMS = Arrays.asList( + "oreAdamant", "blockAdamant", "plateAdamant", "doorAdamant", + "nuggetAdamant", "trapdoorAdamant", "dustAdamant", "gearAdamant", + "rodAdamant", "barsAdamant", "ingotAdamant", "dustTinyAdamant", + "dustSmallAdamant"); + + @EventHandler + public void serverStarted(final FMLServerStartedEvent event) throws IOException { + final boolean expectedTaiga = Boolean.parseBoolean( + requiredProperty("basemetals.probe.expectedTaiga")); + final boolean expectedPrismarine = Boolean.parseBoolean( + requiredProperty("basemetals.probe.expectedPrismarine")); + final boolean expectedConArm = Boolean.parseBoolean( + requiredProperty("basemetals.probe.expectedConArm")); + final ContentMode expectedContentMode = ContentMode.fromSerializedName( + requiredProperty("basemetals.probe.expectedContentMode")); + final File marker = new File(requiredProperty("basemetals.probe.marker")); + final Properties result = new Properties(); + + require(Loader.isModLoaded("basemetals"), "Base Metals did not load"); + require(Loader.isModLoaded("mmdlib"), "MMDLib did not load"); + require(Loader.isModLoaded("orespawn"), "OreSpawn did not load"); + require(Loader.isModLoaded("mantle"), "Mantle did not load"); + require(Loader.isModLoaded("tconstruct"), "Tinkers Construct did not load"); + require(BMeConfig.getActiveContentMode() == expectedContentMode, + "Content mode did not match expected mode " + expectedContentMode + + "; actual=" + BMeConfig.getActiveContentMode()); + require(Loader.isModLoaded("taiga") == expectedTaiga, + "TAIGA loaded state did not match expected state " + expectedTaiga); + require(Loader.isModLoaded("conarm") == expectedConArm, + "Construct's Armory loaded state did not match expected state " + expectedConArm); + verifyPrismarineConfiguration(expectedPrismarine); + verifyCoreContentPolicy(expectedContentMode); + + final Item adamantineIngot = requireItem("basemetals", "adamantine_ingot"); + + verifyBaseAliases("Adamantine"); + verifyBaseAliases("Adamantite"); + verifyBaseAliases("Adamantium"); + + final Fluid adamantineFluid = requireFluid("adamantine"); + + require(meltingFluids(adamantineIngot).equals(singleton(adamantineFluid.getName())), + "Base Metals Adamantine ingot has ambiguous Tinkers melting outputs: " + + meltingFluids(adamantineIngot)); + verifyMaterialStats(expectedContentMode); + verifyArmorMaterialStats(expectedContentMode, expectedConArm); + + if (expectedTaiga) { + require(TAIGA_EMBEDDED_VERSION.equals(version("taiga")), + "Unexpected TAIGA version " + version("taiga")); + verifyNoBaseMetalsAdamantAliases(); + verifyTaigaAliases(); + + final Item taigaAdamantIngot = requireItem("taiga", "adamant_ingot"); + final Fluid taigaAdamantFluid = requireFluid("adamant_fluid"); + + require(adamantineFluid != taigaAdamantFluid, + "Base Metals Adamantine and TAIGA Adamant share one fluid instance"); + require(meltingFluids(taigaAdamantIngot).equals(singleton(taigaAdamantFluid.getName())), + "TAIGA Adamant ingot has ambiguous Tinkers melting outputs: " + + meltingFluids(taigaAdamantIngot)); + } else { + verifyBaseAliases("Adamant"); + require(FluidRegistry.getFluid("adamant_fluid") == null, + "TAIGA Adamant fluid exists when TAIGA is absent"); + } + + result.setProperty("phase", System.getProperty("basemetals.probe.phase", "unknown")); + result.setProperty("taiga", Boolean.toString(expectedTaiga)); + result.setProperty("conarm", Boolean.toString(expectedConArm)); + result.setProperty("prismarine", Boolean.toString(expectedPrismarine)); + result.setProperty("contentMode", expectedContentMode.serializedName()); + + if (expectedTaiga) { + result.setProperty("taigaEmbeddedVersion", version("taiga")); + } + + result.setProperty("adamantineMeltingOutputs", + meltingFluids(adamantineIngot).toString()); + result.setProperty("registered", "true"); + marker.getParentFile().mkdirs(); + + try (FileOutputStream output = new FileOutputStream(marker)) { + result.store(output, "Base Metals Tinkers/TAIGA qualification"); + } + + FMLCommonHandler.instance().getMinecraftServerInstance().initiateShutdown(); + } + + private static void verifyArmorMaterialStats(final ContentMode mode, + final boolean expectedConArm) { + if (!expectedConArm) { + return; + } + + requireStats("adamantine", "adamantine", "core", "plates", "trim"); + + if (mode != ContentMode.HIGH_FANTASY) { + // Use Brass here: Tinkers owns Lead, so its stats must stay untouched. + final Material bismuth = TinkerRegistry.getMaterial("bismuth"); + + require(bismuth != Material.UNKNOWN, + "Missing restricted-mode Tinkers material Bismuth"); + require(!bismuth.hasStats("core") && !bismuth.hasStats("plates") + && !bismuth.hasStats("trim"), + "Restricted mode exposed Bismuth Construct's Armory stats"); + } + } + + private static void verifyCoreContentPolicy(final ContentMode mode) { + // Restricted recipes must not remove items from saves or creative mode. + for (final String path : Arrays.asList("adamantine_bow", "adamantine_pickaxe", + "pewter_chestplate", "bronze_pickaxe", "mercury_ingot")) { + final Item item = requireItem("basemetals", path); + + require(item.getCreativeTab() != null, + "Restricted item is unavailable for creative recovery: " + path); + } + + final boolean high = mode == ContentMode.HIGH_FANTASY; + + verifyRecipeOutput("adamantine_bow", high); + verifyRecipeOutput("adamantine_pickaxe", true); + verifyRecipeOutput("pewter_chestplate", high); + verifyRecipeOutput("bronze_pickaxe", true); + verifyPlateRepairPolicy("steel", true); + verifyPlateRepairPolicy("adamantine", true); + verifyPlateRepairPolicy("pewter", high); + + final ItemStack adamantinePowder = new ItemStack( + requireItem("basemetals", "adamantine_powder")); + final ItemStack adamantineIngot = new ItemStack( + requireItem("basemetals", "adamantine_ingot")); + final ItemStack smelted = FurnaceRecipes.instance().getSmeltingResult(adamantinePowder); + + require(!smelted.isEmpty(), + "Adamantine furnace acquisition does not match " + mode + ": " + smelted); + require(CrusherRecipeRegistry.getRecipeForInputItem(adamantineIngot) != null, + "Adamantine crusher acquisition does not match " + mode); + + final ItemStack mercuryPowder = new ItemStack( + requireItem("basemetals", "mercury_powder")); + final ItemStack mercurySmelted = FurnaceRecipes.instance().getSmeltingResult(mercuryPowder); + + require(!mercurySmelted.isEmpty(), + "Mercury reagent ingot acquisition does not match " + mode + ": " + + mercurySmelted); + } + + private static void verifyPlateRepairPolicy(final String material, + final boolean expectedAllowed) { + final ResourceLocation id = new ResourceLocation("basemetals", + material + "_chestplate_plate_repair"); + final IRecipe recipe = CraftingManager.REGISTRY.getObject(id); + + require(recipe != null, "Missing stable plate-repair identity " + id); + require(recipe.isDynamic(), "Plate repair is visible in the recipe book: " + id); + + final ItemStack armor = new ItemStack(requireItem("basemetals", + material + "_chestplate")); + + armor.setItemDamage(1); + + final InventoryCrafting grid = new InventoryCrafting(new Container() { + @Override + public boolean canInteractWith(final EntityPlayer playerIn) { + return false; + } + }, 3, 3); + + grid.setInventorySlotContents(2, armor); + grid.setInventorySlotContents(7, new ItemStack(requireItem("basemetals", + material + "_plate"))); + + final boolean actual = recipe.matches(grid, + FMLCommonHandler.instance().getMinecraftServerInstance().getEntityWorld()); + + require(actual == expectedAllowed, + "Plate-repair policy for " + id + " expected " + expectedAllowed + + " but matched " + actual); + require(!recipe.getCraftingResult(grid).isEmpty() == expectedAllowed, + "Plate-repair output policy does not match " + id); + } + + private static void verifyRecipeOutput(final String path, final boolean expectedAllowed) { + final ResourceLocation id = new ResourceLocation("basemetals", path); + final IRecipe recipe = CraftingManager.REGISTRY.getObject(id); + + require(recipe != null, "Missing stable recipe identity " + id); + require(!recipe.getRecipeOutput().isEmpty() == expectedAllowed, + "Recipe policy for " + id + " does not match expected allowed=" + + expectedAllowed + "; output=" + recipe.getRecipeOutput()); + require(recipe.isDynamic() != expectedAllowed, + "Recipe-book visibility for " + id + " does not match expected allowed=" + + expectedAllowed); + } + + private static void verifyMaterialStats(final ContentMode mode) { + if (mode == ContentMode.HIGH_FANTASY) { + requireStats("adamantine", "Adamantine", "head", "handle", "extra", "bow", + "bowstring", "shaft", "fletching"); + } else { + verifyRestrictedStats("adamantine", "Adamantine"); + } + } + + private static void verifyRestrictedStats(final String identifier, final String displayName) { + final Material material = TinkerRegistry.getMaterial(identifier); + + require(material != Material.UNKNOWN, "Missing Tinkers material " + identifier); + requireStats(identifier, displayName, "head", "handle", "extra", "shaft", "fletching"); + require(!material.hasStats("bow"), displayName + " exposes restricted bow stats"); + require(!material.hasStats("bowstring"), + displayName + " exposes restricted bowstring stats"); + } + + private static void requireStats(final String materialIdentifier, final String displayName, + final String... identifiers) { + final Material material = TinkerRegistry.getMaterial(materialIdentifier); + + require(material != Material.UNKNOWN, "Missing Tinkers material " + materialIdentifier); + + for (final String identifier : identifiers) { + require(material.hasStats(identifier), + displayName + " is missing Tinkers stats " + identifier); + } + } + + private static void verifyPrismarineConfiguration(final boolean expectedPrismarine) { + final Fluid prismarine = FluidRegistry.getFluid("prismarine"); + + if (expectedPrismarine) { + require(prismarine != null, "Prismarine fluid is missing when enabled"); + + return; + } + + require(prismarine == null, "Prismarine fluid exists when Prismarine additions are disabled"); + + for (final AlloyRecipe recipe : TinkerRegistry.getAlloys()) { + if (recipe.getResult() != null && recipe.getResult().getFluid() != null) { + require(!"aquarium".equals(recipe.getResult().getFluid().getName()), + "Aquarium alloy was registered without molten Prismarine"); + } + } + } + + private static void verifyBaseAliases(final String suffix) { + requireOreEntry("ingot" + suffix, "basemetals", "adamantine_ingot"); + requireOreEntry("dust" + suffix, "basemetals", "adamantine_powder"); + requireOreEntry("nugget" + suffix, "basemetals", "adamantine_nugget"); + requireOreEntry("block" + suffix, "basemetals", "adamantine_block"); + } + + private static void verifyNoBaseMetalsAdamantAliases() { + for (final String oreName : ADAMANT_FORMS) { + for (final ItemStack stack : OreDictionary.getOres(oreName, false)) { + final ResourceLocation registryName = stack.getItem().getRegistryName(); + + require(registryName == null || !"basemetals".equals(registryName.getNamespace()), + "TAIGA-owned Ore Dictionary name " + oreName + + " contains Base Metals item " + registryName); + } + } + } + + private static void verifyTaigaAliases() { + requireOreEntry("ingotAdamant", "taiga", "adamant_ingot"); + requireOreEntry("dustAdamant", "taiga", "adamant_dust"); + requireOreEntry("nuggetAdamant", "taiga", "adamant_nugget"); + requireOreEntry("blockAdamant", "taiga", "adamant_block"); + } + + private static void requireOreEntry( + final String oreName, + final String namespace, + final String path) { + final ResourceLocation expected = new ResourceLocation(namespace, path); + final List actual = new ArrayList<>(); + boolean found = false; + + for (final ItemStack stack : OreDictionary.getOres(oreName, false)) { + final ResourceLocation registryName = stack.getItem().getRegistryName(); + + actual.add(registryName); + + if (expected.equals(registryName)) { + found = true; + } + } + + require(found, "Ore Dictionary name " + oreName + " is missing " + expected + + "; entries=" + actual); + } + + private static Set meltingFluids(final Item item) { + final ItemStack stack = new ItemStack(item); + final Set fluids = new LinkedHashSet<>(); + + for (final MeltingRecipe recipe : TinkerRegistry.getAllMeltingRecipies()) { + if (recipe.matches(stack)) { + fluids.add(recipe.getResult().getFluid().getName()); + } + } + + return fluids; + } + + private static Set singleton(final String value) { + final Set values = new LinkedHashSet<>(); + + values.add(value); + + return values; + } + + private static Item requireItem(final String namespace, final String path) { + final ResourceLocation registryName = new ResourceLocation(namespace, path); + final Item item = Item.REGISTRY.getObject(registryName); + + require(item != null && registryName.equals(item.getRegistryName()), + "Missing item " + registryName); + + return item; + } + + private static Fluid requireFluid(final String name) { + final Fluid fluid = FluidRegistry.getFluid(name); + + require(fluid != null, "Missing fluid " + name); + + return fluid; + } + + private static String version(final String modid) { + return Loader.instance().getIndexedModList().get(modid).getVersion(); + } + + private static String requiredProperty(final String name) { + final String value = System.getProperty(name); + + if (value == null || value.trim().isEmpty()) { + throw new IllegalStateException("Missing system property " + name); + } + + return value; + } + + private static void require(final boolean condition, final String message) { + if (!condition) { + throw new IllegalStateException(message); + } + } } diff --git a/src/test/java/com/mcmoddev/basemetals/util/BaseMetalsConfigContractTest.java b/src/test/java/com/mcmoddev/basemetals/util/BaseMetalsConfigContractTest.java index a43c1fb3..942102ab 100644 --- a/src/test/java/com/mcmoddev/basemetals/util/BaseMetalsConfigContractTest.java +++ b/src/test/java/com/mcmoddev/basemetals/util/BaseMetalsConfigContractTest.java @@ -44,6 +44,7 @@ void exposesTheFiveHistoricalCategoriesAndNinetyThreeSettings() { final Set expectedCategories = BMeConfig.GUI_CATEGORIES.stream() .map(name -> name.toLowerCase(java.util.Locale.ROOT)) .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); + assertEquals(expectedCategories, new LinkedHashSet<>(configuration.getCategoryNames())); assertEquals(2, configuration.getCategory(BMeConfig.GENERAL_CAT).size()); assertEquals(22, configuration.getCategory(BMeConfig.MATERIALS_CAT).size()); @@ -57,14 +58,17 @@ void exposesTheFiveHistoricalCategoriesAndNinetyThreeSettings() { @Test void preservesEveryKeyDefaultCommentAndMarksEveryOptionForRestart() { final Configuration configuration = create(); + assertProperty(configuration, BMeConfig.GENERAL_CAT, "achievements", true, - "If false, then Base Metals Achievements will be disabled (This is currently required if you disable any metals", + "If false, Base Metals gameplay achievements will be disabled. Recipe-book unlocks are unaffected.", "config.basemetals.option.achievements"); + final Property contentMode = configuration.getCategory(BMeConfig.GENERAL_CAT) .get(BMeConfig.CONTENT_MODE_PROPERTY); + assertEquals(Property.Type.STRING, contentMode.getType()); assertEquals(ContentMode.HIGH_FANTASY.serializedName(), contentMode.getString()); - assertEquals(Arrays.asList(ContentMode.serializedNames()), + assertEquals(Arrays.asList("high_fantasy", "low_fantasy"), Arrays.asList(contentMode.getValidValues())); assertEquals(Arrays.asList(ContentMode.translationKeys()), Arrays.asList(contentMode.getValidValuesDisplay())); @@ -72,6 +76,7 @@ void preservesEveryKeyDefaultCommentAndMarksEveryOptionForRestart() { for (final String material : METALS) { final String display = WordUtils.capitalizeFully(material); + assertProperty(configuration, BMeConfig.MATERIALS_CAT, "Enable" + display, true, "Enable " + display + " Items and Materials", materialKey(material)); assertProperty(configuration, BMeConfig.FLUIDS_CAT, "Enabled " + display, true, @@ -84,9 +89,11 @@ void preservesEveryKeyDefaultCommentAndMarksEveryOptionForRestart() { for (final String material : VANILLA) { final String display = WordUtils.capitalizeFully(material); + assertProperty(configuration, BMeConfig.VANILLA_CAT, "Enable" + display, true, "Enable " + display + " Additions like Walls, Slabs and Pressure-plates", materialKey(material)); + if (VANILLA_FLUIDS.contains(material)) { assertProperty(configuration, BMeConfig.FLUIDS_CAT, "Enabled " + display, true, "Enable the molten fluid of " + material, materialKey(material)); @@ -95,9 +102,11 @@ void preservesEveryKeyDefaultCommentAndMarksEveryOptionForRestart() { for (final String categoryName : BMeConfig.GUI_CATEGORIES) { final ConfigCategory category = configuration.getCategory(categoryName); + assertTrue(category.requiresMcRestart(), categoryName); assertTrue(category.requiresWorldRestart(), categoryName); assertNotNull(category.getLanguagekey(), categoryName); + for (final Property property : category.getValues().values()) { if (!BMeConfig.CONTENT_MODE_PROPERTY.equals(property.getName())) { assertEquals(Property.Type.BOOLEAN, property.getType(), property.getName()); @@ -110,6 +119,7 @@ void preservesEveryKeyDefaultCommentAndMarksEveryOptionForRestart() { void missingLegacyModeAndExplicitHighFantasyHaveTheSameEffectiveValue() { final Configuration legacy = new Configuration( tempDirectory.resolve("LegacyBaseMetals.cfg").toFile()); + legacy.get(BMeConfig.GENERAL_CAT, "achievements", false); assertEquals(ContentMode.HIGH_FANTASY, BMeConfig.configuredContentMode(legacy)); assertFalse(legacy.getCategory(BMeConfig.GENERAL_CAT).containsKey( @@ -123,10 +133,12 @@ void missingLegacyModeAndExplicitHighFantasyHaveTheSameEffectiveValue() { @Test void missingPropertyDefaultsToHighFantasyAndInvalidValuesAreCorrectedOnPopulate() { final Configuration absent = create(); + absent.getCategory(BMeConfig.GENERAL_CAT).remove(BMeConfig.CONTENT_MODE_PROPERTY); assertEquals(ContentMode.HIGH_FANTASY, BMeConfig.configuredContentMode(absent)); final Configuration invalid = create(); + invalid.getCategory(BMeConfig.GENERAL_CAT).get(BMeConfig.CONTENT_MODE_PROPERTY) .set("not_a_mode"); BMeConfig.populateConfiguration(invalid); @@ -136,27 +148,51 @@ void missingPropertyDefaultsToHighFantasyAndInvalidValuesAreCorrectedOnPopulate( .get(BMeConfig.CONTENT_MODE_PROPERTY).getString()); } + @Test + void invalidModeDefaultsToHighFantasyWithoutChangingOtherSettings() { + final Configuration configuration = create(); + + configuration.getCategory(BMeConfig.GENERAL_CAT) + .get(BMeConfig.CONTENT_MODE_PROPERTY).set("not_a_mode"); + configuration.getCategory(BMeConfig.MATERIALS_CAT).get("EnableTin").set(false); + configuration.save(); + + final Configuration reloaded = create(); + + assertEquals(ContentMode.HIGH_FANTASY, BMeConfig.configuredContentMode(reloaded)); + assertEquals("high_fantasy", reloaded.getCategory(BMeConfig.GENERAL_CAT) + .get(BMeConfig.CONTENT_MODE_PROPERTY).getString()); + assertFalse(reloaded.getCategory(BMeConfig.MATERIALS_CAT) + .get("EnableTin").getBoolean()); + } + @Test void legacyUpgradePreservesEveryExistingBooleanValue() { final Configuration legacy = create(); final Map expected = new LinkedHashMap<>(); int index = 0; + for (final String categoryName : BMeConfig.GUI_CATEGORIES) { for (final Property property : legacy.getCategory(categoryName).getValues().values()) { if (property.getType() == Property.Type.BOOLEAN) { final boolean value = (index++ & 1) == 0; + property.set(value); expected.put(categoryName + "\u0000" + property.getName(), value); } } } + legacy.getCategory(BMeConfig.GENERAL_CAT).remove(BMeConfig.CONTENT_MODE_PROPERTY); legacy.save(); final Configuration upgraded = create(); + assertEquals(ContentMode.HIGH_FANTASY, BMeConfig.configuredContentMode(upgraded)); + for (final Map.Entry entry : expected.entrySet()) { final String[] key = entry.getKey().split("\u0000", 2); + assertEquals(entry.getValue().booleanValue(), upgraded.getCategory(key[0]).get(key[1]).getBoolean(), entry.getKey()); } @@ -181,6 +217,7 @@ private static void assertProperty(final Configuration configuration, final Stri final String name, final boolean expectedDefault, final String expectedComment, final String expectedLanguageKey) { final Property property = configuration.getCategory(category).get(name); + assertNotNull(property, category + "/" + name); assertEquals(expectedDefault, Boolean.parseBoolean(property.getDefault()), name); assertEquals(expectedComment + " [default: " + expectedDefault + "]", diff --git a/src/test/java/com/mcmoddev/basemetals/util/TestConfigFactory.java b/src/test/java/com/mcmoddev/basemetals/util/TestConfigFactory.java index 71d6d8dd..cc02005a 100644 --- a/src/test/java/com/mcmoddev/basemetals/util/TestConfigFactory.java +++ b/src/test/java/com/mcmoddev/basemetals/util/TestConfigFactory.java @@ -13,14 +13,18 @@ private TestConfigFactory() { public static Configuration create(final File file) { prepareForgeConfigurationHome(file.getParentFile()); + final Configuration configuration = new Configuration(file); + BMeConfig.populateConfiguration(configuration); + return configuration; } private static void prepareForgeConfigurationHome(final File home) { try { final Field minecraftHome = FMLInjectionData.class.getDeclaredField("minecraftHome"); + minecraftHome.setAccessible(true); minecraftHome.set(null, home); } catch (ReflectiveOperationException failure) { diff --git a/tools/gen_block_ingot.js b/tools/gen_block_ingot.js index 6e7afd63..9e909b39 100644 --- a/tools/gen_block_ingot.js +++ b/tools/gen_block_ingot.js @@ -1,17 +1,38 @@ const util = require('util'), - fs = require('fs'); + fs = require('fs'); -const mats = [ "Adamantine", "Antimony", "Bismuth", "ColdIron", "Copper", "Lead", "Nickel", "Platinum", "Silver", "StarSteel", "Tin", "Zinc", - 'Aquarium', 'Brass', 'Bronze', 'Cupronickel', 'Electrum', 'Invar', 'Mithril', 'Pewter', 'Steel' ]; +const mats = [ + 'Adamantine', + 'Antimony', + 'Bismuth', + 'ColdIron', + 'Copper', + 'Lead', + 'Nickel', + 'Platinum', + 'Silver', + 'StarSteel', + 'Tin', + 'Zinc', + 'Aquarium', + 'Brass', + 'Bronze', + 'Cupronickel', + 'Electrum', + 'Invar', + 'Mithril', + 'Pewter', + 'Steel' +]; -function toTitleCase(str) -{ - return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}); +function toTitleCase(str) { + return str.replace(/\w\S*/g, function (txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); + }); } - function getBlockOreDict(str) { - return { type: "forge:ore_dict", ore: `block${toTitleCase(str.toLowerCase())}` }; + return { type: 'forge:ore_dict', ore: `block${toTitleCase(str.toLowerCase())}` }; } function getIngotName(str) { @@ -19,25 +40,27 @@ function getIngotName(str) { } function getConditions(str) { - return { type: "forge:and", - values: [ - { type: "basemetals:enabled", - optionName: "material", - optionValue: str }, - { type: "basemetals:enabled", - optionName: "thing", - optionValue: "basics" } ] }; + return { + type: 'forge:and', + values: [ + { type: 'basemetals:enabled', optionName: 'material', optionValue: str }, + { type: 'basemetals:enabled', optionName: 'thing', optionValue: 'basics' } + ] + }; } function getRecipeFor(str) { - return { type: "forge:ore_shapeless", - ingredients: [ getBlockOreDict(str) ], - result: getIngotName(str), - group: "basics", - conditions: [ getConditions(str) ] }; + return { + type: 'forge:ore_shapeless', + ingredients: [getBlockOreDict(str)], + result: getIngotName(str), + group: 'basics', + conditions: [getConditions(str)] + }; } -for( let i = 0; i < mats.length; i++ ) { +for (let i = 0; i < mats.length; i++) { let f = `output/${mats[i].toLowerCase()}_block_ingot.json`; - fs.writeFileSync( f, JSON.stringify( getRecipeFor(mats[i]), null, '\t' ) ); + + fs.writeFileSync(f, JSON.stringify(getRecipeFor(mats[i]), null, '\t')); } diff --git a/tools/gen_recipes.js b/tools/gen_recipes.js index 24bac40e..e72ca356 100644 --- a/tools/gen_recipes.js +++ b/tools/gen_recipes.js @@ -1,511 +1,1162 @@ const fs = require('fs'); -const base_mats = [ "Adamantine", "Antimony", "Bismuth", "ColdIron", "Copper", "Lead", "Nickel", "Platinum", "Silver", "StarSteel", "Steel", "Tin", "Zinc" ]; -const van_mats = [ "Diamond", "Emerald", "Gold", "Iron", "Stone", "Wood", "Quartz", "Obsidian", "Charcoal", "Coal" ]; +const base_mats = [ + 'Adamantine', + 'Antimony', + 'Bismuth', + 'ColdIron', + 'Copper', + 'Lead', + 'Nickel', + 'Platinum', + 'Silver', + 'StarSteel', + 'Steel', + 'Tin', + 'Zinc' +]; +const van_mats = [ + 'Diamond', + 'Emerald', + 'Gold', + 'Iron', + 'Stone', + 'Wood', + 'Quartz', + 'Obsidian', + 'Charcoal', + 'Coal' +]; -const armor_mats = [ "Adamantine", "Antimony", "Bismuth", "Brass", "Bronze", "ColdIron", "Copper", "Cupronickel", "Diamond", "Electrum", "Emerald", "Gold", "Iron", "Lead", - "Nickel", "Pewter", "Platinum", "Silver", "StarSteel", "Steel", "Tin", "Zinc" ]; +const armor_mats = [ + 'Adamantine', + 'Antimony', + 'Bismuth', + 'Brass', + 'Bronze', + 'ColdIron', + 'Copper', + 'Cupronickel', + 'Diamond', + 'Electrum', + 'Emerald', + 'Gold', + 'Iron', + 'Lead', + 'Nickel', + 'Pewter', + 'Platinum', + 'Silver', + 'StarSteel', + 'Steel', + 'Tin', + 'Zinc' +]; -const armor_pieces = [ 'boots', 'chestplate', 'helmet', 'leggings', 'shield' ]; +const armor_pieces = ['boots', 'chestplate', 'helmet', 'leggings', 'shield']; const _factories = { - "conditions": { - "enabled":"com.mcmoddev.lib.recipe.conditions.ConditionEnabled", - "hammer":"com.mcmoddev.lib.recipe.conditions.hammerEnabled", - "plate":"com.mcmoddev.lib.recipe.conditions.PlateRepairEnabled" - }, - "recipes": { - "variableOutputOre":"com.mcmoddev.lib.recipe.factories.ConfigVariedOutput", - "armor_repair":"com.mcmoddev.lib.recipe.factories.ArmorRepair" + 'conditions': { + 'enabled': 'com.mcmoddev.lib.recipe.conditions.ConditionEnabled', + 'hammer': 'com.mcmoddev.lib.recipe.conditions.hammerEnabled', + 'plate': 'com.mcmoddev.lib.recipe.conditions.PlateRepairEnabled' + }, + 'recipes': { + 'variableOutputOre': 'com.mcmoddev.lib.recipe.factories.ConfigVariedOutput', + 'armor_repair': 'com.mcmoddev.lib.recipe.factories.ArmorRepair' } }; -const alloy_mix = { 'Aquarium': { 'recipe': { 'type': 'forge:ore_shapeless', - 'mix': [ { "type": "oredict", "name": "dustCopper" }, - { "type": "oredict", "name": "dustCopper" }, - { "type": "oredict", "name": "dustZinc" }, - { "type": "oredict", "name": "dustPrismarine" } ] }, - 'output': 3 }, - 'Brass': { 'recipe': { 'type': 'forge:ore_shapeless', - 'mix': [ { "type": "oredict", "name": "dustCopper" }, - { "type": "oredict", "name": "dustCopper" }, - { "type": "oredict", "name": "dustZinc" } ] }, - 'output': 3 }, - 'Bronze': { 'recipe': { 'type': 'forge:ore_shapeless', - 'mix': [ { "type": "oredict", "name": "dustCopper" }, - { "type": "oredict", "name": "dustCopper" }, - { "type": "oredict", "name": "dustCopper" }, - { "type": "oredict", "name": "dustTin" } ] }, - 'output': 4 }, - 'Cupronickel': { 'recipe': { 'type': 'forge:ore_shapeless', - 'mix': [ { "type": "oredict", "name": "dustCopper" }, - { "type": "oredict", "name": "dustCopper" }, - { "type": "oredict", "name": "dustCopper" }, - { "type": "oredict", "name": "dustNickel" } ] }, - 'output': 4 }, - 'Electrum': { 'recipe': { 'type': 'forge:ore_shapeless', - 'mix': [ { "type": "oredict", "name": "dustGold" }, - { "type": "oredict", "name": "dustSilver" } ] }, - 'output': 2 }, - 'Pewter': { 'recipe': { 'type': 'forge:ore_shapeless', - 'mix': [ { "type": "oredict", "name": "dustTin" }, - { "type": "oredict", "name": "dustCopper" }, - { "type": "oredict", "name": "dustLead" } ] }, - 'output': 3 }, - 'Invar': { 'recipe': { 'type': 'forge:ore_shapeless', - 'mix': [ { "type": "oredict", "name":"dustIron"}, - { "type": "oredict", "name":"dustIron"}, - { "type": "oredict", "name":"dustNickel"} ] }, - 'output': 3 }, - 'Steel': { 'recipe': { 'type': 'forge:ore_shapeless', - 'mix': [ { 'type': 'oredict', 'name':'dustIron' }, - { 'type': 'oredict', 'name':'dustIron' }, - { 'type': 'oredict', 'name':'dustIron' }, - { 'type': 'oredict', 'name':'dustIron' }, - { 'type': 'oredict', 'name':'dustIron' }, - { 'type': 'oredict', 'name':'dustIron' }, - { 'type': 'oredict', 'name':'dustIron' }, - { 'type': 'oredict', 'name':'dustIron' }, - { 'type': 'oredict', 'name':'dustCoal' } ] }, - 'output': 8 }, - 'Mithril': { 'recipe': { 'type': 'forge:ore_shapeless', - 'mix': [ { 'type': 'oredict', 'name': 'dustSilver'}, - { 'type': 'oredict', 'name': 'dustColdiron' }, - { 'type': 'oredict', 'name': 'ingotMercury' } ] }, - 'output': 3 } }; - -const alloy_conditions = { 'Aquarium': { 'enabled': [ 'Basics' ], 'materials': [ 'Copper', 'Zinc' ] }, - 'Brass': { 'enabled': [ 'Basics' ], 'materials': [ 'Copper', 'Zinc' ] }, - 'Bronze': { 'enabled': [ 'Basics' ], 'materials': [ 'Copper', 'Tin' ] }, - 'Cupronickel': { 'enabled': [ 'Basics'] , 'materials': [ 'Copper', 'Nickel' ] }, - 'Electrum': { 'enabled': [ 'Basics' ], 'materials': [ 'Silver' ] }, - 'Invar': { 'enabled': [ 'Basics' ], 'materials': [ 'Iron', 'Nickel' ] }, - 'Pewter': { 'enabled': [ 'Basics' ], 'materials': [ 'Copper', 'Lead', 'Tin' ] }, - 'Steel': { 'enabled': [ 'Basics' ], 'materials': [ 'Iron', 'Coal' ] }, - 'Mithril': { 'enabled': [ 'Basics' ], 'materials': [ 'Silver', 'ColdIron', 'Mercury' ] } }; - -const alloy_names = [ 'Aquarium', 'Brass', 'Bronze', 'Cupronickel', 'Electrum', 'Invar', 'Mithril', 'Pewter', 'Steel' ]; +const alloy_mix = { + 'Aquarium': { + 'recipe': { + 'type': 'forge:ore_shapeless', + 'mix': [ + { 'type': 'oredict', 'name': 'dustCopper' }, + { 'type': 'oredict', 'name': 'dustCopper' }, + { 'type': 'oredict', 'name': 'dustZinc' }, + { 'type': 'oredict', 'name': 'dustPrismarine' } + ] + }, + 'output': 3 + }, + 'Brass': { + 'recipe': { + 'type': 'forge:ore_shapeless', + 'mix': [ + { 'type': 'oredict', 'name': 'dustCopper' }, + { 'type': 'oredict', 'name': 'dustCopper' }, + { 'type': 'oredict', 'name': 'dustZinc' } + ] + }, + 'output': 3 + }, + 'Bronze': { + 'recipe': { + 'type': 'forge:ore_shapeless', + 'mix': [ + { 'type': 'oredict', 'name': 'dustCopper' }, + { 'type': 'oredict', 'name': 'dustCopper' }, + { 'type': 'oredict', 'name': 'dustCopper' }, + { 'type': 'oredict', 'name': 'dustTin' } + ] + }, + 'output': 4 + }, + 'Cupronickel': { + 'recipe': { + 'type': 'forge:ore_shapeless', + 'mix': [ + { 'type': 'oredict', 'name': 'dustCopper' }, + { 'type': 'oredict', 'name': 'dustCopper' }, + { 'type': 'oredict', 'name': 'dustCopper' }, + { 'type': 'oredict', 'name': 'dustNickel' } + ] + }, + 'output': 4 + }, + 'Electrum': { + 'recipe': { + 'type': 'forge:ore_shapeless', + 'mix': [ + { 'type': 'oredict', 'name': 'dustGold' }, + { 'type': 'oredict', 'name': 'dustSilver' } + ] + }, + 'output': 2 + }, + 'Pewter': { + 'recipe': { + 'type': 'forge:ore_shapeless', + 'mix': [ + { 'type': 'oredict', 'name': 'dustTin' }, + { 'type': 'oredict', 'name': 'dustCopper' }, + { 'type': 'oredict', 'name': 'dustLead' } + ] + }, + 'output': 3 + }, + 'Invar': { + 'recipe': { + 'type': 'forge:ore_shapeless', + 'mix': [ + { 'type': 'oredict', 'name': 'dustIron' }, + { 'type': 'oredict', 'name': 'dustIron' }, + { 'type': 'oredict', 'name': 'dustNickel' } + ] + }, + 'output': 3 + }, + 'Steel': { + 'recipe': { + 'type': 'forge:ore_shapeless', + 'mix': [ + { 'type': 'oredict', 'name': 'dustIron' }, + { 'type': 'oredict', 'name': 'dustIron' }, + { 'type': 'oredict', 'name': 'dustIron' }, + { 'type': 'oredict', 'name': 'dustIron' }, + { 'type': 'oredict', 'name': 'dustIron' }, + { 'type': 'oredict', 'name': 'dustIron' }, + { 'type': 'oredict', 'name': 'dustIron' }, + { 'type': 'oredict', 'name': 'dustIron' }, + { 'type': 'oredict', 'name': 'dustCoal' } + ] + }, + 'output': 8 + }, + 'Mithril': { + 'recipe': { + 'type': 'forge:ore_shapeless', + 'mix': [ + { 'type': 'oredict', 'name': 'dustSilver' }, + { 'type': 'oredict', 'name': 'dustColdiron' }, + { 'type': 'oredict', 'name': 'ingotMercury' } + ] + }, + 'output': 3 + } +}; + +const alloy_conditions = { + 'Aquarium': { 'enabled': ['Basics'], 'materials': ['Copper', 'Zinc'] }, + 'Brass': { 'enabled': ['Basics'], 'materials': ['Copper', 'Zinc'] }, + 'Bronze': { 'enabled': ['Basics'], 'materials': ['Copper', 'Tin'] }, + 'Cupronickel': { 'enabled': ['Basics'], 'materials': ['Copper', 'Nickel'] }, + 'Electrum': { 'enabled': ['Basics'], 'materials': ['Silver'] }, + 'Invar': { 'enabled': ['Basics'], 'materials': ['Iron', 'Nickel'] }, + 'Pewter': { 'enabled': ['Basics'], 'materials': ['Copper', 'Lead', 'Tin'] }, + 'Steel': { 'enabled': ['Basics'], 'materials': ['Iron', 'Coal'] }, + 'Mithril': { 'enabled': ['Basics'], 'materials': ['Silver', 'ColdIron', 'Mercury'] } +}; + +const alloy_names = [ + 'Aquarium', + 'Brass', + 'Bronze', + 'Cupronickel', + 'Electrum', + 'Invar', + 'Mithril', + 'Pewter', + 'Steel' +]; const patterns_basic = { // Basics - 'nugget': { 'type': 'forge:ore_shapeless', 'input': 'INGOT', 'result': { 'mat': 'NUGGET', 'count': 9 }, 'config': { 'enabled': [ 'Basics' ] }, "group": "basics" }, - 'ingot': { 'type': 'forge:ore_shaped', 'input': [ "xxx", "xxx", "xxx" ], 'key': { 'x': 'NUGGET' }, 'result': { 'mat': 'INGOT', 'count': 1 }, 'config': { 'enabled': [ 'Basics' ] }, "group": "basics" }, - 'block': { 'type': 'forge:ore_shaped', 'input': [ 'xxx', "xxx", "xxx" ], 'key' : { 'x': 'INGOT' }, 'result': { 'mat': 'BLOCK', 'count': 1 }, 'config': { 'enabled': [ 'Basics' ] }, "group": "basics" }, - 'powder': { 'type': 'forge:ore_shaped', 'input': [ 'xxx', 'xxx', 'xxx' ], 'key': { 'x': 'SMALLPOWDER' }, 'result': { 'mat': 'POWDER', 'count': 1 }, 'config': { 'enabled': [ 'Basics' ] }, "group": "basics" }, - 'smallpowder': { 'type': 'forge:ore_shapeless', 'input': 'POWDER', 'result': { 'mat': 'SMALLPOWDER', 'count': 9 }, 'config': { 'enabled': [ 'Basics' ] }, "group": "basics" }, - 'blend': { 'type': 'forge:ore_shaped', 'input': [ 'xxx', 'xxx', 'xxx' ], 'key': { 'x': 'SMALLBLEND' }, 'result': { 'mat': 'BLEND', 'count': 1 }, 'config': { 'enabled': [ 'Basics' ] }, "group": "basics" }, - 'smallblend': { 'type': 'forge:ore_shapeless', 'input': 'BLEND', 'result': { 'mat': 'SMALLBLEND', 'count': 9 }, 'config': { 'enabled': [ 'Basics' ] }, "group": "basics" }, + 'nugget': { + 'type': 'forge:ore_shapeless', + 'input': 'INGOT', + 'result': { 'mat': 'NUGGET', 'count': 9 }, + 'config': { 'enabled': ['Basics'] }, + 'group': 'basics' + }, + 'ingot': { + 'type': 'forge:ore_shaped', + 'input': ['xxx', 'xxx', 'xxx'], + 'key': { 'x': 'NUGGET' }, + 'result': { 'mat': 'INGOT', 'count': 1 }, + 'config': { 'enabled': ['Basics'] }, + 'group': 'basics' + }, + 'block': { + 'type': 'forge:ore_shaped', + 'input': ['xxx', 'xxx', 'xxx'], + 'key': { 'x': 'INGOT' }, + 'result': { 'mat': 'BLOCK', 'count': 1 }, + 'config': { 'enabled': ['Basics'] }, + 'group': 'basics' + }, + 'powder': { + 'type': 'forge:ore_shaped', + 'input': ['xxx', 'xxx', 'xxx'], + 'key': { 'x': 'SMALLPOWDER' }, + 'result': { 'mat': 'POWDER', 'count': 1 }, + 'config': { 'enabled': ['Basics'] }, + 'group': 'basics' + }, + 'smallpowder': { + 'type': 'forge:ore_shapeless', + 'input': 'POWDER', + 'result': { 'mat': 'SMALLPOWDER', 'count': 9 }, + 'config': { 'enabled': ['Basics'] }, + 'group': 'basics' + }, + 'blend': { + 'type': 'forge:ore_shaped', + 'input': ['xxx', 'xxx', 'xxx'], + 'key': { 'x': 'SMALLBLEND' }, + 'result': { 'mat': 'BLEND', 'count': 1 }, + 'config': { 'enabled': ['Basics'] }, + 'group': 'basics' + }, + 'smallblend': { + 'type': 'forge:ore_shapeless', + 'input': 'BLEND', + 'result': { 'mat': 'SMALLBLEND', 'count': 9 }, + 'config': { 'enabled': ['Basics'] }, + 'group': 'basics' + }, // Basic Tools - 'axe': { 'type': 'forge:ore_shaped', 'input': [ 'xx', 'xs', " s" ], 'key': { 'x': 'INGOT', 's': "STICK" }, 'result': { 'mat': 'AXE', 'count': 1 }, 'config': { 'enabled': [ 'Basics', 'BasicTools' ] }, "group": "tools" }, - 'pickaxe': { 'type': 'forge:ore_shaped', 'input': [ 'xxx', " s ", " s " ], 'key': { 'x': 'INGOT', 's': "STICK" }, 'result': { 'mat': 'PICKAXE', 'count': 1 }, 'config': { 'enabled': [ 'Basics', 'BasicTools' ] }, "group": "tools" }, - 'shovel': { 'type': 'forge:ore_shaped', 'input': [ 'x', 's', 's' ], 'key': { 'x': 'INGOT', 's': "STICK" }, 'result': { 'mat': 'SHOVEL', 'count': 1 }, 'config': { 'enabled': [ 'Basics', 'BasicTools' ] }, "group": "tools" }, - 'hoe': { 'type': 'forge:ore_shaped', 'input': [ 'xx', " s", " s" ], 'key': { 'x': 'INGOT', 's': "STICK" }, 'result': { 'mat': 'HOE', 'count': 1 }, 'config': { 'enabled': [ 'Basics', 'BasicTools' ] }, "group": "tools" }, - 'sword': { 'type': 'forge:ore_shaped', 'input': [ 'x', 'x', 's' ], 'key': { 'x': 'INGOT', 's': "STICK" }, 'result': { 'mat': 'SWORD', 'count': 1 }, 'config': { 'enabled': [ 'Basics', 'BasicTools' ] }, "group": "weapon" }, + 'axe': { + 'type': 'forge:ore_shaped', + 'input': ['xx', 'xs', ' s'], + 'key': { 'x': 'INGOT', 's': 'STICK' }, + 'result': { 'mat': 'AXE', 'count': 1 }, + 'config': { 'enabled': ['Basics', 'BasicTools'] }, + 'group': 'tools' + }, + 'pickaxe': { + 'type': 'forge:ore_shaped', + 'input': ['xxx', ' s ', ' s '], + 'key': { 'x': 'INGOT', 's': 'STICK' }, + 'result': { 'mat': 'PICKAXE', 'count': 1 }, + 'config': { 'enabled': ['Basics', 'BasicTools'] }, + 'group': 'tools' + }, + 'shovel': { + 'type': 'forge:ore_shaped', + 'input': ['x', 's', 's'], + 'key': { 'x': 'INGOT', 's': 'STICK' }, + 'result': { 'mat': 'SHOVEL', 'count': 1 }, + 'config': { 'enabled': ['Basics', 'BasicTools'] }, + 'group': 'tools' + }, + 'hoe': { + 'type': 'forge:ore_shaped', + 'input': ['xx', ' s', ' s'], + 'key': { 'x': 'INGOT', 's': 'STICK' }, + 'result': { 'mat': 'HOE', 'count': 1 }, + 'config': { 'enabled': ['Basics', 'BasicTools'] }, + 'group': 'tools' + }, + 'sword': { + 'type': 'forge:ore_shaped', + 'input': ['x', 'x', 's'], + 'key': { 'x': 'INGOT', 's': 'STICK' }, + 'result': { 'mat': 'SWORD', 'count': 1 }, + 'config': { 'enabled': ['Basics', 'BasicTools'] }, + 'group': 'weapon' + }, // Armor - 'boots': { 'type': 'forge:ore_shaped', 'input': [ 'x x', 'x x' ], 'key': { 'x': 'INGOT' }, 'result': { 'mat': 'BOOTS', 'count': 1 }, 'config': { 'enabled': [ 'Basics', 'Armor' ] }, "group": "armor" }, - 'helmet': { 'type': 'forge:ore_shaped', 'input': [ 'xxx', 'x x' ], 'key': { 'x': 'INGOT' }, 'result': { 'mat': 'HELMET', 'count': 1 }, 'config': { 'enabled': [ 'Basics', 'Armor' ] }, "group": "armor" }, - 'chestplate': { 'type': 'forge:ore_shaped', 'input': [ 'x x', 'xxx', 'xxx' ], 'key': { 'x': 'INGOT' }, 'result': { 'mat': 'CHESTPLATE', 'count': 1 }, 'config': { 'enabled': [ 'Basics', 'Armor' ] }, "group": "armor" }, - 'leggings': { 'type': 'forge:ore_shaped', 'input': [ 'xxx', 'x x', 'x x' ], 'key': { 'x': 'INGOT' }, 'result': { 'mat': 'LEGGINGS', 'count': 1 }, 'config': { 'enabled': [ 'Basics', 'Armor' ] }, "group": "armor" }, + 'boots': { + 'type': 'forge:ore_shaped', + 'input': ['x x', 'x x'], + 'key': { 'x': 'INGOT' }, + 'result': { 'mat': 'BOOTS', 'count': 1 }, + 'config': { 'enabled': ['Basics', 'Armor'] }, + 'group': 'armor' + }, + 'helmet': { + 'type': 'forge:ore_shaped', + 'input': ['xxx', 'x x'], + 'key': { 'x': 'INGOT' }, + 'result': { 'mat': 'HELMET', 'count': 1 }, + 'config': { 'enabled': ['Basics', 'Armor'] }, + 'group': 'armor' + }, + 'chestplate': { + 'type': 'forge:ore_shaped', + 'input': ['x x', 'xxx', 'xxx'], + 'key': { 'x': 'INGOT' }, + 'result': { 'mat': 'CHESTPLATE', 'count': 1 }, + 'config': { 'enabled': ['Basics', 'Armor'] }, + 'group': 'armor' + }, + 'leggings': { + 'type': 'forge:ore_shaped', + 'input': ['xxx', 'x x', 'x x'], + 'key': { 'x': 'INGOT' }, + 'result': { 'mat': 'LEGGINGS', 'count': 1 }, + 'config': { 'enabled': ['Basics', 'Armor'] }, + 'group': 'armor' + }, // Misc. - 'arrow': { 'type': 'forge:ore_shaped', 'input': [ 'x', 'y', 'z' ], 'key': { 'x': 'NUGGET', 'y': 'ROD', 'z': 'FEATHER' }, 'result': { 'mat': 'ARROW', 'count': 4 }, 'config': { 'enabled': [ 'BowAndArrow', 'Basics' ] }, "group": "weapon" }, - 'bars_1': { 'type': 'forge:ore_shaped', 'input': [ 'xxx', 'xxx' ], 'key': { 'x': 'INGOT' }, 'result': { 'mat': 'BARS', 'count': 16 }, 'config': { 'enabled': [ 'Bars', 'Basics' ] }, "group": "misc" }, - 'bars_2': { 'type': 'forge:ore_shaped', 'input': [ 'xxx' ], 'key': { 'x': 'ROD' }, 'result': { 'mat': 'BARS', 'count': 4 }, 'config': { 'enabled': [ 'Bars', 'Rod' ] }, "group": "misc" }, - 'bow': { 'type': 'forge:ore_shaped', 'input': [ ' xs', 'x s', ' xs' ], 'key': { 'x': 'ROD', 's': 'STRING' }, 'result': { 'mat': 'BOW', 'count': 1 }, 'config': { 'enabled': [ 'BowAndArrow', 'Rod' ] }, "group": "weapon" }, - 'button': { 'type': 'forge:ore_shaped', 'input': [ 'x', 'x' ], 'key': { 'x': 'NUGGET' }, 'result': { 'mat': 'BUTTON', 'count': 1 }, 'config': { 'enabled': [ 'Button', 'Basics' ] }, "group": "misc" }, - 'bolt': { 'type': 'forge:ore_shaped', 'input': [ 'x', 'x', 'y' ], 'key': { 'x': 'ROD', 'y': 'FEATHER' }, 'result': { 'mat': 'BOLT', 'count': 4 }, 'config': { 'enabled': [ 'CrossbowAndBolt', 'Rod' ] }, "group": "weapon" }, - 'crackhammer': { 'type': 'forge:ore_shaped', 'input': [ 'x', 'y', 'y' ], 'key': { 'x': 'BLOCK', 'y': 'STICK' }, 'result': { 'mat': 'CRACKHAMMER', 'count': 1 }, 'config': { 'enabled': [ 'Basics', 'hammerEnabled' ] }, "group": "tools" }, - 'crossbow': { 'type': 'forge:ore_shaped', 'input': [ 'zxx', ' yx', 'x z' ], 'key': { 'x': 'ROD', 'y': 'STRING', 'z': 'GEAR' }, 'result': { 'mat': 'CROSSBOW', 'count': 1 }, 'config': { 'enabled': [ 'CrossbowAndBolt', 'Rod', 'Gear' ] }, "group": "weapon" }, - 'door': { 'type': 'forge:ore_shaped', 'input': [ 'xx', 'xx', 'xx' ], 'key': { 'x': 'INGOT' }, 'result': { 'mat': 'DOOR', 'count': 3 }, 'config': { 'enabled': [ 'Door', 'Basics' ] }, "group": "misc" }, - 'fishingrod': { 'type': 'forge:ore_shaped', 'input': [ " x", " xy", "x y" ], 'key': { 'x': 'ROD', 'y': 'STRING' }, 'result': { 'mat': 'FISHING_ROD', 'count': 1 }, 'config': { 'enabled': [ 'FishingRod', 'Rod' ] }, "group": "misc" }, - 'gear': { 'type': 'basemetals:variableOutputOre', 'input': [" x ", "xrx", " x " ], 'key': { 'x': 'INGOT', 'r': 'ROD' }, 'result': { 'mat': 'GEAR' }, 'config': { 'enabled': [ 'Gear', 'Basics' ] }, "group": "misc", "config_key":"gear" }, - 'horsearmor': { 'type': 'forge:ore_shaped', 'input': [ " x", 'xyx', 'xxx' ], 'key': { 'x': 'INGOT', 'y': 'WOOL' }, 'result': { 'mat': 'HORSE_ARMOR', 'count': 1 }, 'config': { 'enabled': [ 'HorseArmor', 'Basics' ] }, "group": "armor" }, - 'lever': { 'type': 'forge:ore_shaped', 'input': [ 'x', 'y' ], 'key': { 'x': 'ROD', 'y': 'INGOT' }, 'result': { 'mat': 'LEVER', 'count': 1 }, 'config': { 'enabled': [ 'Lever', 'Rod', 'Basics' ] }, "group": "misc" }, - 'plate': { 'type': 'basemetals:variableOutputOre', 'input': [ 'xxx' ], 'key': { 'x': 'INGOT' }, 'result': { 'mat': 'PLATE' }, 'config': { 'enabled': [ 'Plate', 'Basics' ] }, "group": "misc", "config_key":"plate" }, - 'pressureplate': { 'type': 'forge:ore_shaped', 'input': [ 'xx' ], 'key': { 'x': 'INGOT' }, 'result': { 'mat': 'PRESSUREPLATE', 'count': 1 }, 'config': { 'enabled': [ 'PressurePlate', 'Basics' ] }, "group": "misc" }, - 'rod': { 'type': 'forge:ore_shaped', 'input': [ 'x', 'x' ], 'key' : { 'x': 'INGOT' }, 'result': { 'mat': 'ROD', 'count': 4 }, 'config': { 'enabled': [ 'Rod', 'Basics' ] }, "group": "misc" }, - 'shears': { 'type': 'forge:ore_shaped', 'input': [ " x", "x " ], 'key': { 'x': 'INGOT' }, 'result': { 'mat': 'SHEARS', 'count': 1 }, 'config': { 'enabled': [ 'Shears', 'Basics' ] }, "group": "tools" }, - 'shield': { 'type': 'forge:ore_shaped', 'input': [ 'xyx', 'xxx', ' x ' ], 'key': { 'x': 'INGOT', 'y': 'WOOD_PLANK' }, 'result': { 'mat': 'SHIELD', 'count': 1 }, 'config': { 'enabled': [ 'Shields', 'Basics' ] }, "group": "armor" }, - 'slab': { 'type': 'forge:ore_shaped', 'input': [ 'xxx' ], 'key' : { 'x': 'BLOCK' }, 'result': { 'mat': 'SLAB', 'count': 6 }, 'config': { 'enabled': [ 'Slab', 'Basics' ] }, "group": "misc" }, - 'stairs': { 'type': 'forge:ore_shaped', 'input': [ 'x ', 'xx ', 'xxx' ], 'key' : { 'x': 'BLOCK' }, 'result': { 'mat': 'STAIRS', 'count': 4 }, 'config': { 'enabled': [ 'Stairs', 'Basics' ] }, "group": "misc" }, - 'trapdoor': { 'type': 'forge:ore_shaped', 'input': [ 'xx', 'xx' ], 'key': { 'x': 'INGOT' }, 'result': { 'mat': 'TRAPDOOR', 'count': 1 }, 'config': { 'enabled': [ 'Trapdoor', 'Basics' ] }, "group": "misc" }, - 'wall': { 'type': 'forge:ore_shaped', 'input': [ 'xxx', 'xxx' ], 'key' : { 'x': 'BLOCK' }, 'result': { 'mat': 'WALL', 'count': 6 }, 'config': { 'enabled': [ 'Wall', 'Basics' ] }, "group": "misc" } + 'arrow': { + 'type': 'forge:ore_shaped', + 'input': ['x', 'y', 'z'], + 'key': { 'x': 'NUGGET', 'y': 'ROD', 'z': 'FEATHER' }, + 'result': { 'mat': 'ARROW', 'count': 4 }, + 'config': { 'enabled': ['BowAndArrow', 'Basics'] }, + 'group': 'weapon' + }, + 'bars_1': { + 'type': 'forge:ore_shaped', + 'input': ['xxx', 'xxx'], + 'key': { 'x': 'INGOT' }, + 'result': { 'mat': 'BARS', 'count': 16 }, + 'config': { 'enabled': ['Bars', 'Basics'] }, + 'group': 'misc' + }, + 'bars_2': { + 'type': 'forge:ore_shaped', + 'input': ['xxx'], + 'key': { 'x': 'ROD' }, + 'result': { 'mat': 'BARS', 'count': 4 }, + 'config': { 'enabled': ['Bars', 'Rod'] }, + 'group': 'misc' + }, + 'bow': { + 'type': 'forge:ore_shaped', + 'input': [' xs', 'x s', ' xs'], + 'key': { 'x': 'ROD', 's': 'STRING' }, + 'result': { 'mat': 'BOW', 'count': 1 }, + 'config': { 'enabled': ['BowAndArrow', 'Rod'] }, + 'group': 'weapon' + }, + 'button': { + 'type': 'forge:ore_shaped', + 'input': ['x', 'x'], + 'key': { 'x': 'NUGGET' }, + 'result': { 'mat': 'BUTTON', 'count': 1 }, + 'config': { 'enabled': ['Button', 'Basics'] }, + 'group': 'misc' + }, + 'bolt': { + 'type': 'forge:ore_shaped', + 'input': ['x', 'x', 'y'], + 'key': { 'x': 'ROD', 'y': 'FEATHER' }, + 'result': { 'mat': 'BOLT', 'count': 4 }, + 'config': { 'enabled': ['CrossbowAndBolt', 'Rod'] }, + 'group': 'weapon' + }, + 'crackhammer': { + 'type': 'forge:ore_shaped', + 'input': ['x', 'y', 'y'], + 'key': { 'x': 'BLOCK', 'y': 'STICK' }, + 'result': { 'mat': 'CRACKHAMMER', 'count': 1 }, + 'config': { 'enabled': ['Basics', 'hammerEnabled'] }, + 'group': 'tools' + }, + 'crossbow': { + 'type': 'forge:ore_shaped', + 'input': ['zxx', ' yx', 'x z'], + 'key': { 'x': 'ROD', 'y': 'STRING', 'z': 'GEAR' }, + 'result': { 'mat': 'CROSSBOW', 'count': 1 }, + 'config': { 'enabled': ['CrossbowAndBolt', 'Rod', 'Gear'] }, + 'group': 'weapon' + }, + 'door': { + 'type': 'forge:ore_shaped', + 'input': ['xx', 'xx', 'xx'], + 'key': { 'x': 'INGOT' }, + 'result': { 'mat': 'DOOR', 'count': 3 }, + 'config': { 'enabled': ['Door', 'Basics'] }, + 'group': 'misc' + }, + 'fishingrod': { + 'type': 'forge:ore_shaped', + 'input': [' x', ' xy', 'x y'], + 'key': { 'x': 'ROD', 'y': 'STRING' }, + 'result': { 'mat': 'FISHING_ROD', 'count': 1 }, + 'config': { 'enabled': ['FishingRod', 'Rod'] }, + 'group': 'misc' + }, + 'gear': { + 'type': 'basemetals:variableOutputOre', + 'input': [' x ', 'xrx', ' x '], + 'key': { 'x': 'INGOT', 'r': 'ROD' }, + 'result': { 'mat': 'GEAR' }, + 'config': { 'enabled': ['Gear', 'Basics'] }, + 'group': 'misc', + 'config_key': 'gear' + }, + 'horsearmor': { + 'type': 'forge:ore_shaped', + 'input': [' x', 'xyx', 'xxx'], + 'key': { 'x': 'INGOT', 'y': 'WOOL' }, + 'result': { 'mat': 'HORSE_ARMOR', 'count': 1 }, + 'config': { 'enabled': ['HorseArmor', 'Basics'] }, + 'group': 'armor' + }, + 'lever': { + 'type': 'forge:ore_shaped', + 'input': ['x', 'y'], + 'key': { 'x': 'ROD', 'y': 'INGOT' }, + 'result': { 'mat': 'LEVER', 'count': 1 }, + 'config': { 'enabled': ['Lever', 'Rod', 'Basics'] }, + 'group': 'misc' + }, + 'plate': { + 'type': 'basemetals:variableOutputOre', + 'input': ['xxx'], + 'key': { 'x': 'INGOT' }, + 'result': { 'mat': 'PLATE' }, + 'config': { 'enabled': ['Plate', 'Basics'] }, + 'group': 'misc', + 'config_key': 'plate' + }, + 'pressureplate': { + 'type': 'forge:ore_shaped', + 'input': ['xx'], + 'key': { 'x': 'INGOT' }, + 'result': { 'mat': 'PRESSUREPLATE', 'count': 1 }, + 'config': { 'enabled': ['PressurePlate', 'Basics'] }, + 'group': 'misc' + }, + 'rod': { + 'type': 'forge:ore_shaped', + 'input': ['x', 'x'], + 'key': { 'x': 'INGOT' }, + 'result': { 'mat': 'ROD', 'count': 4 }, + 'config': { 'enabled': ['Rod', 'Basics'] }, + 'group': 'misc' + }, + 'shears': { + 'type': 'forge:ore_shaped', + 'input': [' x', 'x '], + 'key': { 'x': 'INGOT' }, + 'result': { 'mat': 'SHEARS', 'count': 1 }, + 'config': { 'enabled': ['Shears', 'Basics'] }, + 'group': 'tools' + }, + 'shield': { + 'type': 'forge:ore_shaped', + 'input': ['xyx', 'xxx', ' x '], + 'key': { 'x': 'INGOT', 'y': 'WOOD_PLANK' }, + 'result': { 'mat': 'SHIELD', 'count': 1 }, + 'config': { 'enabled': ['Shields', 'Basics'] }, + 'group': 'armor' + }, + 'slab': { + 'type': 'forge:ore_shaped', + 'input': ['xxx'], + 'key': { 'x': 'BLOCK' }, + 'result': { 'mat': 'SLAB', 'count': 6 }, + 'config': { 'enabled': ['Slab', 'Basics'] }, + 'group': 'misc' + }, + 'stairs': { + 'type': 'forge:ore_shaped', + 'input': ['x ', 'xx ', 'xxx'], + 'key': { 'x': 'BLOCK' }, + 'result': { 'mat': 'STAIRS', 'count': 4 }, + 'config': { 'enabled': ['Stairs', 'Basics'] }, + 'group': 'misc' + }, + 'trapdoor': { + 'type': 'forge:ore_shaped', + 'input': ['xx', 'xx'], + 'key': { 'x': 'INGOT' }, + 'result': { 'mat': 'TRAPDOOR', 'count': 1 }, + 'config': { 'enabled': ['Trapdoor', 'Basics'] }, + 'group': 'misc' + }, + 'wall': { + 'type': 'forge:ore_shaped', + 'input': ['xxx', 'xxx'], + 'key': { 'x': 'BLOCK' }, + 'result': { 'mat': 'WALL', 'count': 6 }, + 'config': { 'enabled': ['Wall', 'Basics'] }, + 'group': 'misc' + } }; -const recipes = [ 'nugget','ingot','block','powder','smallpowder','axe','pickaxe','shovel','hoe','sword', - 'boots','helmet','chestplate','leggings','arrow','bars_1','bars_2','bow','button','bolt','crackhammer', - 'crossbow','door','fishingrod','gear','horsearmor','lever','plate','pressureplate','rod','shears','shield','slab','stairs','trapdoor','wall' ]; - -const vanilla_map = { "Diamond": [ 'powder', 'smallpowder', 'arrow', 'bars_1', 'bars_2', 'bow', 'button', 'bolt', 'crackhammer', 'crossbow', 'door', 'fishingrod', 'gear', 'lever', 'pressureplate', 'rod', 'stairs', 'slab', 'shield', - 'shears', 'trapdoor', 'wall' ], - "Emerald": [ 'powder', 'smallpowder', 'sword', 'shovel', 'hoe', 'axe', 'pickaxe', 'boots', 'helmet', 'chestplate', 'leggings', 'arrow', 'bars_1', 'bars_2', 'bow', 'button', 'bolt', 'crackhammer', 'crossbow', 'door', - 'fishingrod', 'gear', 'horsearmor', 'lever', 'pressureplate', 'rod', 'stairs', 'slab', 'shield', 'shears', 'trapdoor', 'wall' ], - "Gold": [ 'powder', 'smallpowder', 'arrow', 'bars_1', 'bars_2', 'bow', 'button', 'bolt', 'crackhammer', 'crossbow', 'door', 'fishingrod', 'gear', 'lever', 'plate', 'rod', 'stairs', 'slab', 'shield', 'shears', - 'trapdoor', 'wall' ], - "Iron": [ 'powder', 'smallpowder', 'arrow', 'bars_2', 'bow', 'button', 'bolt', 'crackhammer', 'crossbow', 'fishingrod', 'gear', 'lever', 'plate', 'rod', 'stairs', 'slab', 'shield', 'trapdoor', 'wall' ], - "Stone": [ 'crackhammer' ], - "Wood": [ 'crackhammer' ], - "Quartz": [ 'powder', 'smallpowder', 'nugget', 'ingot', 'sword', 'shovel', 'hoe', 'axe', 'pickaxe', 'boots', 'helmet', 'chestplate', 'leggings', 'arrow', 'bars_1', 'bars_2', 'bow', 'button', 'bolt', 'crackhammer', 'crossbow', 'door', - 'fishingrod', 'gear', 'horsearmor', 'lever', 'pressureplate', 'rod', 'shield', 'shears', 'trapdoor', 'wall' ], - "Obsidian": [ 'powder', 'smallpowder', 'nugget', 'ingot', 'block', 'sword', 'shovel', 'hoe', 'axe', 'pickaxe', 'boots', 'helmet', 'chestplate', 'leggings', 'arrow', 'bars_1', 'bars_2', 'bow', 'button', 'bolt', 'crackhammer', 'crossbow', 'door', - 'fishingrod', 'gear', 'horsearmor', 'lever', 'pressureplate', 'rod', 'stairs', 'slab', 'shield', 'shears', 'trapdoor', 'wall' ], - "Coal": [ 'powder', 'smallpowder', 'nugget', 'ingot' ], - "Charcoal": [ 'powder', 'smallpowder', 'block', 'nugget', 'ingot' ] }; - -function toTitleCase(str) -{ - return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}); +const recipes = [ + 'nugget', + 'ingot', + 'block', + 'powder', + 'smallpowder', + 'axe', + 'pickaxe', + 'shovel', + 'hoe', + 'sword', + 'boots', + 'helmet', + 'chestplate', + 'leggings', + 'arrow', + 'bars_1', + 'bars_2', + 'bow', + 'button', + 'bolt', + 'crackhammer', + 'crossbow', + 'door', + 'fishingrod', + 'gear', + 'horsearmor', + 'lever', + 'plate', + 'pressureplate', + 'rod', + 'shears', + 'shield', + 'slab', + 'stairs', + 'trapdoor', + 'wall' +]; + +const vanilla_map = { + 'Diamond': [ + 'powder', + 'smallpowder', + 'arrow', + 'bars_1', + 'bars_2', + 'bow', + 'button', + 'bolt', + 'crackhammer', + 'crossbow', + 'door', + 'fishingrod', + 'gear', + 'lever', + 'pressureplate', + 'rod', + 'stairs', + 'slab', + 'shield', + 'shears', + 'trapdoor', + 'wall' + ], + 'Emerald': [ + 'powder', + 'smallpowder', + 'sword', + 'shovel', + 'hoe', + 'axe', + 'pickaxe', + 'boots', + 'helmet', + 'chestplate', + 'leggings', + 'arrow', + 'bars_1', + 'bars_2', + 'bow', + 'button', + 'bolt', + 'crackhammer', + 'crossbow', + 'door', + 'fishingrod', + 'gear', + 'horsearmor', + 'lever', + 'pressureplate', + 'rod', + 'stairs', + 'slab', + 'shield', + 'shears', + 'trapdoor', + 'wall' + ], + 'Gold': [ + 'powder', + 'smallpowder', + 'arrow', + 'bars_1', + 'bars_2', + 'bow', + 'button', + 'bolt', + 'crackhammer', + 'crossbow', + 'door', + 'fishingrod', + 'gear', + 'lever', + 'plate', + 'rod', + 'stairs', + 'slab', + 'shield', + 'shears', + 'trapdoor', + 'wall' + ], + 'Iron': [ + 'powder', + 'smallpowder', + 'arrow', + 'bars_2', + 'bow', + 'button', + 'bolt', + 'crackhammer', + 'crossbow', + 'fishingrod', + 'gear', + 'lever', + 'plate', + 'rod', + 'stairs', + 'slab', + 'shield', + 'trapdoor', + 'wall' + ], + 'Stone': ['crackhammer'], + 'Wood': ['crackhammer'], + 'Quartz': [ + 'powder', + 'smallpowder', + 'nugget', + 'ingot', + 'sword', + 'shovel', + 'hoe', + 'axe', + 'pickaxe', + 'boots', + 'helmet', + 'chestplate', + 'leggings', + 'arrow', + 'bars_1', + 'bars_2', + 'bow', + 'button', + 'bolt', + 'crackhammer', + 'crossbow', + 'door', + 'fishingrod', + 'gear', + 'horsearmor', + 'lever', + 'pressureplate', + 'rod', + 'shield', + 'shears', + 'trapdoor', + 'wall' + ], + 'Obsidian': [ + 'powder', + 'smallpowder', + 'nugget', + 'ingot', + 'block', + 'sword', + 'shovel', + 'hoe', + 'axe', + 'pickaxe', + 'boots', + 'helmet', + 'chestplate', + 'leggings', + 'arrow', + 'bars_1', + 'bars_2', + 'bow', + 'button', + 'bolt', + 'crackhammer', + 'crossbow', + 'door', + 'fishingrod', + 'gear', + 'horsearmor', + 'lever', + 'pressureplate', + 'rod', + 'stairs', + 'slab', + 'shield', + 'shears', + 'trapdoor', + 'wall' + ], + 'Coal': ['powder', 'smallpowder', 'nugget', 'ingot'], + 'Charcoal': ['powder', 'smallpowder', 'block', 'nugget', 'ingot'] +}; + +function toTitleCase(str) { + return str.replace(/\w\S*/g, function (txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); + }); } const OreDictMaps = { - 'NUGGET': (name) => { return `ore:nugget${toTitleCase(name)}`; }, - 'INGOT': (name) => { return `ore:ingot${toTitleCase(name)}`; }, - 'POWDER': (name) => { return `ore:dust${toTitleCase(name)}`; }, - 'BLEND': (name) => { return `ore:blend${toTitleCase(name)}`; }, - 'SMALLPOWDER': (name) => { return `ore:dustTiny${toTitleCase(name)}`; }, - 'SMALLBLEND': (name) => { return `ore:dustTiny${toTitleCase(name)}`; }, - 'STICK': (name) => { return 'ore:stickWood'; }, - 'WOOD_PLANK': (name) => { return 'ore:plankWood'; }, - 'BLOCK': (name) => { return `ore:block${toTitleCase(name)}`; }, - 'WOOL': (name) => { return 'minecraft:wool'; } + 'NUGGET': (name) => { + return `ore:nugget${toTitleCase(name)}`; + }, + 'INGOT': (name) => { + return `ore:ingot${toTitleCase(name)}`; + }, + 'POWDER': (name) => { + return `ore:dust${toTitleCase(name)}`; + }, + 'BLEND': (name) => { + return `ore:blend${toTitleCase(name)}`; + }, + 'SMALLPOWDER': (name) => { + return `ore:dustTiny${toTitleCase(name)}`; + }, + 'SMALLBLEND': (name) => { + return `ore:dustTiny${toTitleCase(name)}`; + }, + 'STICK': (name) => { + return 'ore:stickWood'; + }, + 'WOOD_PLANK': (name) => { + return 'ore:plankWood'; + }, + 'BLOCK': (name) => { + return `ore:block${toTitleCase(name)}`; + }, + 'WOOL': (name) => { + return 'minecraft:wool'; + } }; function mapName(rawName, matName) { - switch( rawName ) { - case 'STRING': - case 'FEATHER': - return "minecraft:"+rawName.toLowerCase(); - case 'PRESSUREPLATE': - return "basemetals:"+matName.toLowerCase()+"_pressure_plate"; - default: - if( OreDictMaps.hasOwnProperty(rawName) ) { - return OreDictMaps[rawName](matName); - } + switch (rawName) { + case 'STRING': + case 'FEATHER': + return 'minecraft:' + rawName.toLowerCase(); + case 'PRESSUREPLATE': + return 'basemetals:' + matName.toLowerCase() + '_pressure_plate'; + default: + if (OreDictMaps.hasOwnProperty(rawName)) { + return OreDictMaps[rawName](matName); + } } let name = rawName.toLowerCase(); let mname = matName.toLowerCase(); - + return `basemetals:${mname}_${name}`; } -const special_ingots = [ 'Coal', 'Charcoal', 'Diamond', 'Emerald', 'Quartz', 'Obsidian' ]; - -function mapNameOutput( rawName, matName ) { - switch( rawName ) { - case 'INGOT': - if( special_ingots.includes( matName ) ) { - return `minecraft:${matName.toLowerCase()}`; - } else if( van_mats.includes( matName ) ) { - return `minecraft:${matName.toLowerCase()}_ingot`; - } else { - return `basemetals:${matName.toLowerCase()}_ingot`; - } - case 'BARS': - if( matName.toLowerCase() == "iron" ) { - return 'minecraft:iron_bars'; - } else { - return `basemetals:${matName.toLowerCase()}_bars`; - } - case 'SHEARS': - if( matName.toLowerCase() == "iron" ) { - return 'minecraft:shears'; - } else { - return `basemetals:${matName.toLowerCase()}_shears`; - } - case 'BLOCK': - if( matName.toLowerCase() == "obsidian" ) { - return 'minecraft:obsidian'; - } else { - if( van_mats.includes(matName) ) { - return `minecraft:${matName.toLowerCase()}_block`; - } else { - return `basemetals:${matName.toLowerCase()}_block`; - } - } - case 'WOOD': - case 'WOOD_PLANK': - case 'STICK': - case 'STRING': - case 'FEATHER': - return "minecraft:"+rawName.toLowerCase(); - case 'PRESSUREPLATE': - return "basemetals:"+matName.toLowerCase()+"_pressure_plate"; - case 'WOOL': - return 'minecraft:wool'; - default: - return "basemetals:"+matName.toLowerCase()+"_"+rawName.toLowerCase(); +const special_ingots = ['Coal', 'Charcoal', 'Diamond', 'Emerald', 'Quartz', 'Obsidian']; + +function mapNameOutput(rawName, matName) { + switch (rawName) { + case 'INGOT': + if (special_ingots.includes(matName)) { + return `minecraft:${matName.toLowerCase()}`; + } else if (van_mats.includes(matName)) { + return `minecraft:${matName.toLowerCase()}_ingot`; + } else { + return `basemetals:${matName.toLowerCase()}_ingot`; + } + case 'BARS': + if (matName.toLowerCase() == 'iron') { + return 'minecraft:iron_bars'; + } else { + return `basemetals:${matName.toLowerCase()}_bars`; + } + case 'SHEARS': + if (matName.toLowerCase() == 'iron') { + return 'minecraft:shears'; + } else { + return `basemetals:${matName.toLowerCase()}_shears`; + } + case 'BLOCK': + if (matName.toLowerCase() == 'obsidian') { + return 'minecraft:obsidian'; + } else { + if (van_mats.includes(matName)) { + return `minecraft:${matName.toLowerCase()}_block`; + } else { + return `basemetals:${matName.toLowerCase()}_block`; + } + } + case 'WOOD': + case 'WOOD_PLANK': + case 'STICK': + case 'STRING': + case 'FEATHER': + return 'minecraft:' + rawName.toLowerCase(); + case 'PRESSUREPLATE': + return 'basemetals:' + matName.toLowerCase() + '_pressure_plate'; + case 'WOOL': + return 'minecraft:wool'; + default: + return 'basemetals:' + matName.toLowerCase() + '_' + rawName.toLowerCase(); } } function processKey(recipe_key, mat) { let res = {}; var ks = Object.keys(recipe_key); - for( let k = 0; k < ks.length; k++ ) { - res[ks[k]] = processIngredient( recipe_key[ks[k]], mat ); + for (let k = 0; k < ks.length; k++) { + res[ks[k]] = processIngredient(recipe_key[ks[k]], mat); } return res; } function processOutputs(recipe_outputs, mat) { - let res = { "item": mapNameOutput( recipe_outputs.mat, mat ), "data": 0 }; - if( recipe_outputs.count > 1 ) { - res.count = recipe_outputs.count; + let res = { 'item': mapNameOutput(recipe_outputs.mat, mat), 'data': 0 }; + if (recipe_outputs.count > 1) { + res.count = recipe_outputs.count; } return res; } -function processConditions( conditions, mat ) { - var _conds = [ { "type": "basemetals:enabled", - "optionName": "material", - "optionValue": mat - } ]; - - for( let c = 0; c < conditions.length; c++ ) { - var cur = conditions[c]; - if( cur == 'hammerEnabled' ) { - _conds.push( { "type": "basemetals:hammer" } ); - } else { - _conds.push( { "type": "basemetals:enabled", "optionName": "thing", "optionValue": cur } ); - } +function processConditions(conditions, mat) { + var _conds = [{ 'type': 'basemetals:enabled', 'optionName': 'material', 'optionValue': mat }]; + + for (let c = 0; c < conditions.length; c++) { + var cur = conditions[c]; + if (cur == 'hammerEnabled') { + _conds.push({ 'type': 'basemetals:hammer' }); + } else { + _conds.push({ 'type': 'basemetals:enabled', 'optionName': 'thing', 'optionValue': cur }); + } } - var res = [ { - "type": "forge:and", - "values": _conds - } ]; + var res = [ + { + 'type': 'forge:and', + 'values': _conds + } + ]; return res; } -function processIngredients( inputs, mat ) { +function processIngredients(inputs, mat) { let res = []; - for( let i = 0; i < inputs.length; i++ ) { - res.push( processIngredient(inputs[i], mat) ); + + for (let i = 0; i < inputs.length; i++) { + res.push(processIngredient(inputs[i], mat)); } return res; } -function processIngredient( input, mat ) { +function processIngredient(input, mat) { let res = {}; - let name = mapName(input,mat); - if( name.startsWith("ore:") ) { - res = { "type": "forge:ore_dict", "ore": name.split(':')[1] }; - } else if( name == "minecraft:wool" ) { - res = { item: name, data: 32767 }; + let name = mapName(input, mat); + + if (name.startsWith('ore:')) { + res = { 'type': 'forge:ore_dict', 'ore': name.split(':')[1] }; + } else if (name == 'minecraft:wool') { + res = { item: name, data: 32767 }; } else { - res = { "item": name, "data": 0 }; + res = { 'item': name, 'data': 0 }; } return res; } -function processRecipe( mat, rec ) { +function processRecipe(mat, rec) { var this_recipe = rec; - let res = {}; // zero out the result on each loop + let res = {}; + res.type = this_recipe.type; - switch( this_recipe.type ) { - case 'forge:ore_shaped': - res.result = processOutputs( this_recipe.result, mat ); - res.pattern = this_recipe.input; - res.key = processKey(this_recipe.key, mat); - res.conditions = processConditions( this_recipe.config.enabled, mat ); - break; - case 'forge:ore_shapeless': - res.result = processOutputs( this_recipe.result, mat ); - // this isn't the right thing here, but... - res.ingredients = [ processIngredient( this_recipe.input, mat ) ]; - res.conditions = processConditions( this_recipe.config.enabled, mat ); - break; - case 'basemetals:variableOutputOre': - res.result = processOutputs( this_recipe.result, mat ); - res.pattern = this_recipe.input; - res.key = processKey(this_recipe.key, mat); - res.conditions = processConditions( this_recipe.config.enabled, mat ); - res.config_key = rec.config_key; - break; + + switch (this_recipe.type) { + case 'forge:ore_shaped': + res.result = processOutputs(this_recipe.result, mat); + res.pattern = this_recipe.input; + res.key = processKey(this_recipe.key, mat); + res.conditions = processConditions(this_recipe.config.enabled, mat); + break; + case 'forge:ore_shapeless': + res.result = processOutputs(this_recipe.result, mat); + res.ingredients = [processIngredient(this_recipe.input, mat)]; + res.conditions = processConditions(this_recipe.config.enabled, mat); + break; + case 'basemetals:variableOutputOre': + res.result = processOutputs(this_recipe.result, mat); + res.pattern = this_recipe.input; + res.key = processKey(this_recipe.key, mat); + res.conditions = processConditions(this_recipe.config.enabled, mat); + res.config_key = rec.config_key; + break; } + res.group = this_recipe.group; + return res; } -function processMat( mat ) { - for( let x = 0; x < recipes.length; x++ ) { - let res = processRecipe( mat, patterns_basic[recipes[x]] ); - let matFileName = mat.toLowerCase(); - let recFileName = recipes[x].toLowerCase(); - fs.writeFileSync( `output/${matFileName}_${recFileName}.json`, JSON.stringify(res, null, '\t' ) ); +function processMat(mat) { + for (let x = 0; x < recipes.length; x++) { + let res = processRecipe(mat, patterns_basic[recipes[x]]); + let matFileName = mat.toLowerCase(); + let recFileName = recipes[x].toLowerCase(); + + fs.writeFileSync(`output/${matFileName}_${recFileName}.json`, JSON.stringify(res, null, '\t')); } } -function processAlloyConditions( conds, mat ) { +function processAlloyConditions(conds, mat) { let m = conds.materials; let res = []; - for( let i = 0; i < m.length; i++ ) { - res.push( { "type":"basemetals:enabled", "optionName":"material","optionValue":m[i] } ); + + for (let i = 0; i < m.length; i++) { + res.push({ 'type': 'basemetals:enabled', 'optionName': 'material', 'optionValue': m[i] }); } let e = conds.enabled; - for( let x = 0; x < e.length; e++ ) { - res.push( { "type":"basemetals:enabled", "optionName":"thing", "optionValue":e[x] } ); + + for (let x = 0; x < e.length; e++) { + res.push({ 'type': 'basemetals:enabled', 'optionName': 'thing', 'optionValue': e[x] }); } + return res; } -function processAlloyIngredient( ing ) { +function processAlloyIngredient(ing) { let type = ing.type; let name = ing.name; - switch( type ) { - case "oredict": - return { "type":"forge:ore_dict", "ore":name }; - default: - return { "item":name, "data":0 }; + switch (type) { + case 'oredict': + return { 'type': 'forge:ore_dict', 'ore': name }; + default: + return { 'item': name, 'data': 0 }; } } -function getBlendItem( mat ) { +function getBlendItem(mat) { let name = mat.toLowerCase(); + return `basemetals:${name}_blend`; } -function processAlloy( mat ) { +function processAlloy(mat) { var name = mat; var this_mix = alloy_mix[name]; - var this_blend = { "item": getBlendItem(name), "data": 0, "count": this_mix.output }; + var this_blend = { 'item': getBlendItem(name), 'data': 0, 'count': this_mix.output }; var conds = alloy_conditions[name]; var res = {}; + res.result = this_blend; res.type = this_mix.recipe.type; res.ingredients = []; - for( let x = 0; x < this_mix.recipe.mix.length; x++ ) { - res.ingredients.push( processAlloyIngredient( this_mix.recipe.mix[x] ) ); + + for (let x = 0; x < this_mix.recipe.mix.length; x++) { + res.ingredients.push(processAlloyIngredient(this_mix.recipe.mix[x])); } - res.group = "alloys"; - let tnc = processAlloyConditions(conds,name); - tnc.push( { "type":"basemetals:enabled", "optionName":"material","optionValue":name } ); - - res.conditions = [ { "type":"forge:and", "values": tnc } ]; + + res.group = 'alloys'; + + let tnc = processAlloyConditions(conds, name); + + tnc.push({ 'type': 'basemetals:enabled', 'optionName': 'material', 'optionValue': name }); + + res.conditions = [{ 'type': 'forge:and', 'values': tnc }]; + return res; } -// Basic Materials that get just about everything -for( let i = 0; i < base_mats.length; i++ ) { +// Standard material recipes. +for (let i = 0; i < base_mats.length; i++) { let mat = base_mats[i]; - processMat( mat ); + + processMat(mat); } -// alloys get all the same recipes as the rest, just more - which follows this -for( let i = 0; i < alloy_names.length; i++ ) { +// Alloys use the standard recipes as well as the blend recipes below. +for (let i = 0; i < alloy_names.length; i++) { let mat = alloy_names[i]; - processMat( mat ); + + processMat(mat); } -// Blend->Small Blend, Small Blend->Blend and the base Blend recipes -for( let x = 0; x < alloy_names.length; x++ ) { +// Alloy blends and their small-blend conversions. +for (let x = 0; x < alloy_names.length; x++) { let mat = alloy_names[x]; - let res_blend_1 = processAlloy( mat ); - let res_small_blend = processRecipe( mat, patterns_basic['smallblend'] ); - let res_blend_2 = processRecipe( mat, patterns_basic['blend'] ); + let res_blend_1 = processAlloy(mat); + let res_small_blend = processRecipe(mat, patterns_basic['smallblend']); + let res_blend_2 = processRecipe(mat, patterns_basic['blend']); let matFileName = mat.toLowerCase(); - fs.writeFileSync( `output/${matFileName}_blend_base.json`, JSON.stringify(res_blend_1, null, '\t' ) ); - fs.writeFileSync( `output/${matFileName}_blend_smallblend.json`, JSON.stringify(res_blend_2, null, '\t' ) ); - fs.writeFileSync( `output/${matFileName}_smallblend_blend.json`, JSON.stringify(res_small_blend, null, '\t' ) ); + fs.writeFileSync(`output/${matFileName}_blend_base.json`, JSON.stringify(res_blend_1, null, '\t')); + fs.writeFileSync(`output/${matFileName}_blend_smallblend.json`, JSON.stringify(res_blend_2, null, '\t')); + fs.writeFileSync( + `output/${matFileName}_smallblend_blend.json`, + JSON.stringify(res_small_blend, null, '\t') + ); } -function mapNameVanilla( typeName, matName ) { - +function mapNameVanilla(typeName, matName) { let name = matName.toLowerCase(); - switch( typeName ) { - case 'BLOCK': - switch( name ) { - case 'charcoal': - return 'basemetals:charcoal_block'; - default: - return `minecraft:${name}_block`; - } - break; - case 'INGOT': - switch( matName.toLowerCase() ) { - case 'coal': - case 'diamond': - case 'charcoal': - case 'emerald': - return `minecraft:${name}`; - default: - return `minecraft:${name}_ingot`; - } - break; - case 'BARS': - if( matName.toLowerCase() == "iron" ) { - return 'minecraft:iron_bars'; - } - return `basemetals:${name}_bars`; + switch (typeName) { + case 'BLOCK': + switch (name) { + case 'charcoal': + return 'basemetals:charcoal_block'; + default: + return `minecraft:${name}_block`; + } + break; + case 'INGOT': + switch (matName.toLowerCase()) { + case 'coal': + case 'diamond': + case 'charcoal': + case 'emerald': + return `minecraft:${name}`; + default: + return `minecraft:${name}_ingot`; + } + break; + case 'BARS': + if (matName.toLowerCase() == 'iron') { + return 'minecraft:iron_bars'; + } + return `basemetals:${name}_bars`; } } -// Vanilla Materials -// Needs lots of special handling - for ingot, block and some other bits -for( let v = 0; v < van_mats.length; v++ ) { +// Vanilla materials need their own item names and charcoal metadata. +for (let v = 0; v < van_mats.length; v++) { let recipes = vanilla_map[van_mats[v]]; let matFileName = van_mats[v].toLowerCase(); - for( let r = 0; r < recipes.length; r++ ) { - let recName = recipes[r]; - let recipe = patterns_basic[recName]; - let res = processRecipe( van_mats[v], recipe ); - if( van_mats[v].toLowerCase() == "charcoal" && - recName.toLowerCase() == "ingot" ) { - res.result = { "item":"minecraft:coal", "data":1 }; - } - res.group = "vanilla"; - let recFileName = recName.toLowerCase(); - - fs.writeFileSync( `output/${matFileName}_${recFileName}.json`, JSON.stringify( res, null, '\t' ) ); + for (let r = 0; r < recipes.length; r++) { + let recName = recipes[r]; + let recipe = patterns_basic[recName]; + let res = processRecipe(van_mats[v], recipe); + if (van_mats[v].toLowerCase() == 'charcoal' && recName.toLowerCase() == 'ingot') { + res.result = { 'item': 'minecraft:coal', 'data': 1 }; + } + res.group = 'vanilla'; + let recFileName = recName.toLowerCase(); + + fs.writeFileSync(`output/${matFileName}_${recFileName}.json`, JSON.stringify(res, null, '\t')); } } -// Armor stuff -for( let am = 0; am < armor_mats.length; am++ ) { +// Repair armor and shields with matching plates. +for (let am = 0; am < armor_mats.length; am++) { let this_mat = armor_mats[am]; - for( let at = 0; at < armor_pieces.length; at++ ) { - let this_type = armor_pieces[at]; - let res = { "type": "basemetals:armor_repair", "armorType": this_type, "material":this_mat, "conditions": [ - { "type": "forge:and", - "values": [ - { - "type": "basemetals:enabled", - "optionName": "material", - "optionValue": this_mat - }, - { - "type": "basemetals:enabled", - "optionName": "thing", - "optionValue": "Armor" - }, - { - "type": "basemetals:enabled", - "optionName": "thing", - "optionValue": "Plate" - }, - { - "type": "basemetals:plate" - } - ] - } - ] }; - let fName = `output/${this_mat}_${this_type}_plate_repair.json`.toLowerCase(); - fs.writeFileSync( fName, JSON.stringify( res, null, '\t' ) ); + for (let at = 0; at < armor_pieces.length; at++) { + let this_type = armor_pieces[at]; + let res = { + 'type': 'basemetals:armor_repair', + 'armorType': this_type, + 'material': this_mat, + 'conditions': [ + { + 'type': 'forge:and', + 'values': [ + { + 'type': 'basemetals:enabled', + 'optionName': 'material', + 'optionValue': this_mat + }, + { + 'type': 'basemetals:enabled', + 'optionName': 'thing', + 'optionValue': 'Armor' + }, + { + 'type': 'basemetals:enabled', + 'optionName': 'thing', + 'optionValue': 'Plate' + }, + { + 'type': 'basemetals:plate' + } + ] + } + ] + }; + let fName = `output/${this_mat}_${this_type}_plate_repair.json`.toLowerCase(); + fs.writeFileSync(fName, JSON.stringify(res, null, '\t')); } } - -fs.writeFileSync( 'output/_factories.json', JSON.stringify( _factories, null, '\t' ) ); +fs.writeFileSync('output/_factories.json', JSON.stringify(_factories, null, '\t')); -const blargh = [ "Adamantine", "Antimony", "Aquarium", "Bismuth", "Brass", "Bronze", "ColdIron", "Copper", "Cupronickel", "Electrum", "Emerald", "Invar", "Lead", "Mithril", "Nickel", "Obsidian", "Pewter", "Platinum", "Quartz", "Silver", "StarSteel", "Steel", "Tin", "Zinc" ] +const blargh = [ + 'Adamantine', + 'Antimony', + 'Aquarium', + 'Bismuth', + 'Brass', + 'Bronze', + 'ColdIron', + 'Copper', + 'Cupronickel', + 'Electrum', + 'Emerald', + 'Invar', + 'Lead', + 'Mithril', + 'Nickel', + 'Obsidian', + 'Pewter', + 'Platinum', + 'Quartz', + 'Silver', + 'StarSteel', + 'Steel', + 'Tin', + 'Zinc' +]; -blargh.forEach( (name) => { - fs.writeFileSync( `output/${name.toLowerCase()}_horsearmor.json`, JSON.stringify( processRecipe( name, patterns_basic.horsearmor ), null, '\t' ) ); +blargh.forEach((name) => { + fs.writeFileSync( + `output/${name.toLowerCase()}_horsearmor.json`, + JSON.stringify(processRecipe(name, patterns_basic.horsearmor), null, '\t') + ); }); -console.log( 'done!' ); +console.log('done!'); diff --git a/tools/os3-format-upgrade/convert-to-2.0.js b/tools/os3-format-upgrade/convert-to-2.0.js index f029f44a..31b64836 100644 --- a/tools/os3-format-upgrade/convert-to-2.0.js +++ b/tools/os3-format-upgrade/convert-to-2.0.js @@ -1,34 +1,50 @@ -const fs = require("fs"), - util = require("util"), - console = require("console"); +const fs = require('fs'), + util = require('util'), + console = require('console'); const input_file = process.argv[2]; const output_file = process.argv[3]; -const original_data = JSON.parse( fs.readFileSync( input_file ) ); +const original_data = JSON.parse(fs.readFileSync(input_file)); -const new_data = { "version": "2.0", "spawns": {} }; +const new_data = { 'version': '2.0', 'spawns': {} }; -for( var i = 0; i < original_data.dimensions.length; i++ ) { +for (var i = 0; i < original_data.dimensions.length; i++) { var this_dim = original_data.dimensions[i]; - var curDim = this_dim.hasOwnProperty('dimension')?this_dim.dimension:Math.PI; + var curDim = this_dim.hasOwnProperty('dimension') ? this_dim.dimension : Math.PI; var spawns = this_dim.ores; - for( var j = 0; j < spawns.length; j++ ) { - let dimBlock = [ curDim ]; - if( curDim == Math.PI ) dimBlock = []; - var ns = { "retrogen": false, "enabled": true, "feature": spawns[j].feature, "replaces": spawns[j].replace_block, "dimensions": dimBlock , "biomes": { "excludes": [] }, "parameters": spawns[j].parameters }; - var block = { "name": spawns[j].block, "chance": 100 }; - if( spawns[j].hasOwnProperty('metaData') ) { - block.metaData = spawns[j].metaData; - } else if( spawns[j].hasOwnProperty('state') ) { - block.state = spawns[j].state; - } - var name = block.name.split(":")[1]; - ns.blocks = [ block ]; - new_data.spawns[name] = ns; + + for (var j = 0; j < spawns.length; j++) { + let dimBlock = [curDim]; + + if (curDim == Math.PI) { + dimBlock = []; + } + + var ns = { + 'retrogen': false, + 'enabled': true, + 'feature': spawns[j].feature, + 'replaces': spawns[j].replace_block, + 'dimensions': dimBlock, + 'biomes': { 'excludes': [] }, + 'parameters': spawns[j].parameters + }; + var block = { 'name': spawns[j].block, 'chance': 100 }; + + if (spawns[j].hasOwnProperty('metaData')) { + block.metaData = spawns[j].metaData; + } else if (spawns[j].hasOwnProperty('state')) { + block.state = spawns[j].state; + } + + var name = block.name.split(':')[1]; + + ns.blocks = [block]; + new_data.spawns[name] = ns; } } -var out = JSON.stringify( new_data, null, "\t" ); +var out = JSON.stringify(new_data, null, '\t'); -fs.writeFileSync( output_file, out ); +fs.writeFileSync(output_file, out); diff --git a/tools/os3-format-upgrade/os1-to-os3.js b/tools/os3-format-upgrade/os1-to-os3.js index 49e56429..f03d449a 100644 --- a/tools/os3-format-upgrade/os1-to-os3.js +++ b/tools/os3-format-upgrade/os1-to-os3.js @@ -1,49 +1,58 @@ -const fs = require("fs"), - util = require("util"), - console = require("console"); +const fs = require('fs'), + util = require('util'), + console = require('console'); const input_file = process.argv[2]; const output_file = process.argv[3]; -const original_data = JSON.parse( fs.readFileSync( input_file ) ); +const original_data = JSON.parse(fs.readFileSync(input_file)); -const new_data = { "version": "2.0", "spawns": {} }; +const new_data = { 'version': '2.0', 'spawns': {} }; -for( var i = 0; i < original_data.dimensions.length; i++ ) { +for (var i = 0; i < original_data.dimensions.length; i++) { var this_dim = original_data.dimensions[i]; - let dimBlock = this_dim.dimension=="+"?[]:[this_dim.dimension]; - for( var j = 0; j < this_dim.ores.length; j++ ) { - var this_spawn = this_dim.ores[j]; - var parameters = {}; - parameters.size = this_spawn.size; - parameters.variation = this_spawn.variation; - parameters.frequency = this_spawn.frequency; - parameters.minHeight = this_spawn.minHeight; - parameters.maxHeight = this_spawn.maxHeight; - let biomeBlock = { "excludes": [] }; - if( this_spawn.hasOwnProperty("biomes") ) { - biomeBlock = this_spawn.biomes.length>0?{ "includes": this_dim.biomes }:{ "excludes": [] }; - } - var ns = { - "retrogen": false, - "enabled": true, - "feature": "default", - "replaces": "default", - "dimensions": dimBlock , - "biomes": biomeBlock, - "parameters": parameters }; - var block = { "name": this_spawn.blockID, "chance": 100 }; - if( this_spawn.hasOwnProperty('metaData') ) { - block.metaData = this_spawn.metaData; - } else if( this_spawn.hasOwnProperty('state') ) { - block.state = this_spawn.state; - } - var name = block.name.split(":")[1]; - ns.blocks = [ block ]; - new_data.spawns[name] = ns; + let dimBlock = this_dim.dimension == '+' ? [] : [this_dim.dimension]; + + for (var j = 0; j < this_dim.ores.length; j++) { + var this_spawn = this_dim.ores[j]; + var parameters = {}; + + parameters.size = this_spawn.size; + parameters.variation = this_spawn.variation; + parameters.frequency = this_spawn.frequency; + parameters.minHeight = this_spawn.minHeight; + parameters.maxHeight = this_spawn.maxHeight; + + let biomeBlock = { 'excludes': [] }; + + if (this_spawn.hasOwnProperty('biomes')) { + biomeBlock = this_spawn.biomes.length > 0 ? { 'includes': this_dim.biomes } : { 'excludes': [] }; + } + + var ns = { + 'retrogen': false, + 'enabled': true, + 'feature': 'default', + 'replaces': 'default', + 'dimensions': dimBlock, + 'biomes': biomeBlock, + 'parameters': parameters + }; + var block = { 'name': this_spawn.blockID, 'chance': 100 }; + + if (this_spawn.hasOwnProperty('metaData')) { + block.metaData = this_spawn.metaData; + } else if (this_spawn.hasOwnProperty('state')) { + block.state = this_spawn.state; + } + + var name = block.name.split(':')[1]; + + ns.blocks = [block]; + new_data.spawns[name] = ns; } } -var out = JSON.stringify( new_data, null, "\t" ); +var out = JSON.stringify(new_data, null, '\t'); -fs.writeFileSync( output_file, out ); +fs.writeFileSync(output_file, out); From fd07a8ae06ef5f0e67b14d5ddf8de7ccb6a3b1ff Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Thu, 1 Oct 2026 11:21:19 +0100 Subject: [PATCH 6/6] Keep CI dependencies and CoFH fixtures in the right place Resolve CurseForge files only from CurseMaven or the verified CI mirror, avoiding unrelated Maven Central lookups. Keep the permanent CoFH World fixture tracked and report a missing fixture before starting the server. The packaged CoFH fresh/reload tests and release audit pass locally. --- .gitignore | 1 + build.gradle | 25 +++++++--------- .../verification/packaged-forge-cofh.gradle | 6 +++- .../cofh/world/99_basemetals_issue_448.json | 30 +++++++++++++++++++ 4 files changed, 47 insertions(+), 15 deletions(-) create mode 100644 src/test/resources/cofh/world/99_basemetals_issue_448.json diff --git a/.gitignore b/.gitignore index fe874240..194e9fae 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ **/run-data/ **/saves/ **/world/ +!/src/test/resources/cofh/world/ **/logs/ **/crash-reports/ **/*.log diff --git a/build.gradle b/build.gradle index a8a52149..1b4ca865 100644 --- a/build.gradle +++ b/build.gradle @@ -163,13 +163,18 @@ repositories { maven fg.forgeMaven maven fg.minecraftLibsMaven - if (providers.gradleProperty('legacyDependencyVerificationRepository').isPresent()) { - maven { - name = 'LegacyDependencyVerificationMirror' - url = uri(providers.gradleProperty('legacyDependencyVerificationRepository').get()) - metadataSources { artifact() } - content { includeGroup('curse.maven') } + // CurseForge files belong only in the verified CI mirror or CurseMaven. + exclusiveContent { + forRepository { + maven { + def verificationRepository = providers.gradleProperty('legacyDependencyVerificationRepository') + name = verificationRepository.isPresent() ? 'LegacyDependencyVerificationMirror' : 'CurseMaven' + url = verificationRepository.isPresent() + ? uri(verificationRepository.get()) : uri('https://www.cursemaven.com') + metadataSources { artifact() } + } } + filter { includeGroup('curse.maven') } } exclusiveContent { @@ -187,14 +192,6 @@ repositories { name = 'MinecraftLibraries' url = 'https://libraries.minecraft.net/' } - if (!providers.gradleProperty('legacyDependencyVerificationRepository').isPresent()) { - maven { - name = 'CurseMaven' - url = 'https://www.cursemaven.com' - metadataSources { artifact() } - content { includeGroup('curse.maven') } - } - } } apply from: 'gradle/dependencies.gradle' diff --git a/gradle/verification/packaged-forge-cofh.gradle b/gradle/verification/packaged-forge-cofh.gradle index 68464403..9b0fcb0f 100644 --- a/gradle/verification/packaged-forge-cofh.gradle +++ b/gradle/verification/packaged-forge-cofh.gradle @@ -33,13 +33,17 @@ def prepareCoFH = tasks.register('preparePackagedForgeCoFHWorldRuntime') { File config = new File(cofhRunDirectory, 'config') File cofhWorld = new File(config, 'cofh/world') cofhWorld.mkdirs() + File cofhFixture = file('src/test/resources/cofh/world/99_basemetals_issue_448.json') + if (!cofhFixture.isFile()) { + throw new GradleException("Missing CoFH World test fixture: ${cofhFixture}") + } copy { from file('docs/examples/basemetals-orespawn-disabled.json') into config rename { 'basemetals-orespawn.json' } } copy { - from file('src/test/resources/cofh/world/99_basemetals_issue_448.json') + from cofhFixture into cofhWorld } } diff --git a/src/test/resources/cofh/world/99_basemetals_issue_448.json b/src/test/resources/cofh/world/99_basemetals_issue_448.json new file mode 100644 index 00000000..eebbdfb3 --- /dev/null +++ b/src/test/resources/cofh/world/99_basemetals_issue_448.json @@ -0,0 +1,30 @@ +{ + "dependencies": [ + "basemetals", + "cofhworld" + ], + "namespace": "basemetals_issue_448", + "populate": { + "antimony": { + "enabled": true, + "distribution": "uniform", + "generator": { + "type": "cluster", + "block": "basemetals:antimony_ore", + "material": "minecraft:stone", + "cluster-size": 8 + }, + "cluster-count": 20, + "min-height": 5, + "max-height": 60, + "retrogen": false, + "biome": "all", + "dimension": { + "restriction": "whitelist", + "value": [ + 0 + ] + } + } + } +}