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 000000000..0457356be --- /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 000000000..6104faf6e --- /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 000000000..5a29b9942 --- /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 598682152..710e8e372 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 000000000..06f795b11 --- /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 000000000..cc6223df5 --- /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 bc1ca2d04..3f5193efd 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 dd5385bb3..000000000 --- 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 5ea27611f..e92a18880 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 1975ed96d..d4d8b9a4b 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 9c2042340..ad9340df6 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 000000000..016bea126 --- /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 000000000..56afd629d --- /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 a95009c3b..dbe66e1d6 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 874e1c96d..249efbb03 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 e95643d6a..a51ec4f58 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 f74c120a5..6505ca5e9 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 4fad6ec15..35cc458b1 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 349b36457..10635e8cc 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 adca71c6d..0c03b9e26 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 000000000..fe1e9effe --- /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 e92a18880..d2ccffb83 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 d4d8b9a4b..7f4511971 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 56afd629d..940402e1d 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 d2ccffb83..c3d0708e4 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 7f4511971..c4248437f 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 7c2ae4c00..bbf165be8 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 6104faf6e..9658c4009 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 600a852ee..773e17160 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 c4248437f..5d92b0c6f 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 000000000..274f79be0 --- /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 000000000..8e0596ba5 --- /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 000000000..47781f142 --- /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 ad9340df6..619cba34b 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 000000000..c06a15025 --- /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 000000000..8d02a3b2f --- /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 000000000..123e294b3 --- /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 000000000..d20941bd8 --- /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 000000000..bd36bca42 --- /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 940402e1d..6ecb64304 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 000000000..684644036 --- /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 000000000..5542c1a35 --- /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 000000000..741d3334c --- /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 000000000..3703e7b25 --- /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 000000000..8a4aa0d3b --- /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 000000000..aac89495d --- /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 000000000..65a2f5a18 --- /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 c855e2fe6..416a3404e 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 35cc458b1..880f03236 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 000000000..fca4a2974 --- /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 000000000..4736117d1 --- /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 000000000..367360338 --- /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 000000000..9ef40eb9e --- /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 000000000..1287ac53e --- /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 245ed3cb3..d780881bf 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 8dea5acfa..559428d8a 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 e6f046bbf..ceca912b7 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 3e41b3135..c53a705da 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 584413d4f..0d08c24dd 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 c59214a81..a07365a0a 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 75c805776..1a6f599f5 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 48f799d87..9dea21ebd 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 48d0cf038..8d3b9d23c 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 10635e8cc..000000000 --- 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 5d0ec0a15..6b827d6e4 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 bb56978dd..415f20a44 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 7c3596d69..46bf6ac33 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 d909d6e57..9a80d53a2 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 f8d11e1d5..2be8b7e1b 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 3699d8ad6..f80c54854 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 74a82026d..6056514c2 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 bd1e2ec94..d8730ee58 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 000000000..d78b490a2 --- /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 000000000..512422c81 --- /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 000000000..9350c1fc0 --- /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 000000000..2fe07b11f --- /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 000000000..8427df3e4 --- /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 000000000..5fb5cfe28 --- /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 000000000..e09b74e0f --- /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 000000000..924a3a084 --- /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 000000000..ccd116438 --- /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 000000000..f9d05dfba --- /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 eda3bb89b..544e3bb28 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 e68182e34..f0f80e074 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 ead7531c5..d36c702da 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 bc3fab8a7..449c6a0da 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 f3afc41c9..8f75be154 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 3b64cc6d9..be36531e9 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 fca940ac6..0307f9a14 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 54bd0c692..9222c3765 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 652e75061..b7ae40a8d 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 67176e27e..484ffed57 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 e023dbf3b..ed49f6ce5 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 2220f80e5..2283a77bf 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 f94590f0e..3f707e3c3 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 8ca1ff530..21d7cc54f 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 b62c4c5ab..1e0a2d5b6 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 000000000..319206e14 --- /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 000000000..dcf76b3f0 --- /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 000000000..58777d9b4 --- /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 65b1f404f..43ad36324 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 8c4b3a564..e21fe1aad 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 1b6807f5e..1be733add 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 01a1dc680..7f9afcd1a 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 910e87f58..ff2ab325c 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 05844bee2..b12d210f2 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 474f916b0..ffc2aa45a 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 be4b22268..811dbba3c 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 000000000..6d81c21a7 --- /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 941e2ea1d..000000000 --- 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 000000000..98d795dad --- /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 443e7f691..d8f1a7a35 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 fb03bda5a..8cd379bc9 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 3cf8f516b..1e4f3a686 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 fb03bda5a..8cd379bc9 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 a470833c1..72da6795c 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 30481a99d..7893487e4 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..fe85ad010 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 a470833c1..72da6795c 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 554f19b70..22a498208 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 d4f5bf699..8195c3e04 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 aa2f4b298..eb6ace7fd 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 3bd261e35..fc22a2cd3 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 ba52bd74d..21142cce6 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 29d67a055..fdd53bcc4 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 cbd43e95d..88d79f619 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 243866fae..8d95b9878 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 174ff8315..a36ef1941 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 a6ad0a3ea..142c01ab5 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 e01fe7712..ab9a58d9a 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 ba2af567c..3260fcbda 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 c5e99b77d..efbce7755 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 32b4459c3..b8091dd20 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 4ead682e0..2082e999b 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 ec306dbff..6891ace50 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 516abac72..e296e15e8 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 4764bc300..ca741b9cc 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 5d2671bf0..7c07e3624 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 b854187d7..1d3bb9106 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 672be0e3c..b210a85ae 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 8faeaa38c..e7c8d33f5 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 52434d1de..e14da20ad 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 0207a2fb4..d614a11bb 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 2962b415a..2f03b039f 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 8a6599d04..98877a530 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 7df31e6b6..648544ba2 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 26fca7528..887533124 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 de3267f0d..4f0718ac9 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 4b721e09a..0645f48c6 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 98779c72a..575c3683c 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 4e7df9063..c36153ff9 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 1df66f76f..9d1b4596c 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 2d4793b26..e83694335 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 b927991bb..cd8bab038 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 3b9c87584..13d6a1f53 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 78fc3e09a..ee5e65e9a 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 000000000..865932899 --- /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 000000000..58f526a32 --- /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 000000000..949aa86b4 --- /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 000000000..25473cde0 --- /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 000000000..5270244e0 --- /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 000000000..d859b9333 --- /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 000000000..2b90f5a83 --- /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 000000000..38f8eef69 --- /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 000000000..6610c76c8 --- /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 4ac8ff908..000000000 --- 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 000000000..256c24b9e --- /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 000000000..c8f72296e --- /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 fe1e9effe..1d351caf5 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 000000000..5cfdca334 --- /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 000000000..a43c1fb39 --- /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 000000000..71d6d8ddd --- /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 bf4a6b59a..6c4f56917 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 000000000..398b7cef7 --- /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 0899d53c8..4b481884f 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 3f5193efd..fe8742408 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 c3d0708e4..be5094717 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 773e17160..d40eaced6 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 5d92b0c6f..a8a521495 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 274f79be0..fc0932e88 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 47781f142..e9a56e342 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 c06a15025..144935ed1 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 000000000..f5913d7ef --- /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 000000000..57c375d5b --- /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 d20941bd8..f77a05fb1 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 bd36bca42..16d8dd899 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 000000000..1e71e8585 --- /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 5542c1a35..beb2c4f25 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 3703e7b25..4c73ba3b2 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 8a4aa0d3b..21d4d056a 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 aac89495d..24b75d5af 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 65a2f5a18..41ca614bc 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 880f03236..87dfcc7ef 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 c254e55b6..cc1bba875 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 000000000..689dd5ab4 --- /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 000000000..63c00c9bf --- /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 fca4a2974..975c71383 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 000000000..9bee92d49 --- /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 4736117d1..d77047546 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 367360338..45d795e5e 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 9ef40eb9e..9542937c1 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 1287ac53e..fc468fb82 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 ceca912b7..56d6db8aa 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 c53a705da..a9acdc352 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 a07365a0a..a4b44b7f7 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 1a6f599f5..f2716d854 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 9dea21ebd..3d20d910a 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 8d3b9d23c..1d7128971 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 6b827d6e4..ae66597f6 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 415f20a44..dc7d30291 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 46bf6ac33..bbd8f92aa 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 9a80d53a2..5ad5b4207 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 2be8b7e1b..756ace4fb 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 67f171e5f..3b0618fb1 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 f80c54854..587a9abad 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 6056514c2..2b6a5271f 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 d78b490a2..5eaeeccf2 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 512422c81..51785a432 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 9350c1fc0..d2c15a420 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 2fe07b11f..71ffbd60c 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 8427df3e4..5acd2f477 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 5fb5cfe28..6dea684f2 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 e09b74e0f..a6d7f02fa 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 ccd116438..2e48c34c4 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 f9d05dfba..3d36ebe6a 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 544e3bb28..020535a26 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 f0f80e074..8078bcb9f 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 d36c702da..785fa1991 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 449c6a0da..11afd5845 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 8f75be154..476932824 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 be36531e9..1398db97f 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 0307f9a14..fc7787ee5 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 9222c3765..118899917 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 b7ae40a8d..ba999e841 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 484ffed57..260a70cf4 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 ed49f6ce5..f0247a4e1 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 2283a77bf..864daf3fc 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 3f707e3c3..3844525b7 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 21d7cc54f..5141d6096 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 319206e14..8b7a7bfa7 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 000000000..b8da4585a --- /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 000000000..b874b7ba9 --- /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 dcf76b3f0..8bf9d7f12 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 58777d9b4..d91110c48 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 43ad36324..8e2bba818 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 e21fe1aad..36e417cad 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 1be733add..eb02f7d61 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 7f9afcd1a..83634bca0 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 ff2ab325c..24ee68c45 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 b12d210f2..0f24ca3bb 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 ffc2aa45a..fe1bcc075 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 6d81c21a7..67770cf11 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 000000000..0eed28f4b --- /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 eb6ace7fd..7d406d3f8 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 fc22a2cd3..3008e80c8 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 21142cce6..d7a2a041e 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 fdd53bcc4..37bf4ca5a 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 88d79f619..b65342bbc 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 8d95b9878..b76c4fb39 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 a36ef1941..8e7347f50 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 142c01ab5..6c8b9bbb8 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 ab9a58d9a..f2e0febf4 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 3260fcbda..ea82991ea 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 efbce7755..cbd767f6a 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 b8091dd20..3edd0b355 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 2082e999b..fa6bef288 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 6891ace50..ffeefe01e 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 e296e15e8..998f71190 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 ca741b9cc..5776a9bae 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 7c07e3624..3fe24db12 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 1d3bb9106..268cb6245 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 f55fe1297..a93bcb266 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 b210a85ae..544cc5171 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 b238919f0..27182026a 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 f28d8cda9..4c44e24fb 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 c69ff654c..3050f0fad 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 337b7f7ed..98f91ff9a 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 994bdb192..2bbe3108c 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 94e0d0fc2..a538d5fd0 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 3ef809db0..998d91353 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 8b985eb43..bb25b8aa3 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 ec27e4207..44c2c4743 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 0f9e89447..1d4af5507 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 42de84ac0..bb681fa25 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 6762a4643..accbe1d0c 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 0b8c06020..70fd051c3 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 ec6e7d3d6..af92d841f 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 6854f0d51..0d4718c89 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 bac01ebd7..ef7387784 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 785ca9f81..a423782b5 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 fe17232b2..4181d1ef2 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 2c05ba121..db6f40eee 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 99b0c0796..bedf6a0f2 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 c29868439..113257a85 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 24fba249d..853e855bc 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 d1fecfe96..1e1ca5e4a 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 2b828d3c6..d7921c7f2 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 313cdc98e..2279c8498 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 35cff2ecb..b17c70483 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 352d52335..24de1343e 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 47caba583..66ad5c5c2 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 a964707fc..b244c2128 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 0c4c0433c..0e2ca6408 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 ea7f55785..0befd8836 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 0a0ba8706..e5b4e9a8e 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 f5e1edf25..b834ed328 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 68e93ab23..1b564431e 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 faaa0ce97..a23668d5c 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 bffecc60e..8562770bb 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 82dc6575d..d4a0d3b2b 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 ab27b22e1..64d2ce4ab 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 489709ed7..c33075837 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 64c178bf7..426ae705c 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 9c6bfbea3..3ea8f13d7 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 6f35e55e2..98de3cc45 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 cc16025cd..66fd41738 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 cee2af557..2b923a925 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 cd47f6503..92df9f10b 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 9b2216346..bcbcbdc9f 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 3dfe636ae..51a066e06 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 c19d92a47..3dc09ed7f 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 a2381506a..5ab113132 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 316ec1696..c9dcdd54a 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 cb449d8e6..0e4f46092 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 cd4865288..94c7980f2 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 8164bc82b..2f9d7918d 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 98a7db4a4..891011b34 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 f9142c45c..37a53bc6c 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 95b0f4675..7929b41ae 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 dc021af22..84a187e61 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 a2ae48fee..872f49f51 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 d93fa3cf3..913549f30 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 f05dca0fd..881886960 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 84ed72540..e39dd3c30 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 a459840a7..0808d35cc 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 77fd3d8f7..d7fceb1f4 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 337e09269..1b54c70fb 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 6904dea29..8abb23933 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 98ab95a45..9f953b5ef 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 7ab2276a5..75a30a37f 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 5e43daf29..90fc9a937 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 d33eaf081..973d82b7b 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 8bfa00c2a..bbd476f45 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 84db5d3ce..d26402b02 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 9a55ccd23..b091ec700 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 c0a44982c..2e5583262 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 f5f8709d6..217b8bc0b 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 052f14454..f8c22bf82 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 1f4e7c1ea..6ecc52fcc 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 316e5baa5..50bc95d24 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 2c38c8b36..6dbd9f993 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 1d171f779..55814007e 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 eb4c4d01f..7d9dd26be 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 96514d772..c0d27ca26 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 5370e5209..041b863ea 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 ba483944f..d697a6bd8 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 913abb322..3e75efa6a 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 57d513542..068cf8b56 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 e1e9ae43b..ac2023d26 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 dcc8fc8c5..de47a3cd4 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 1b5a64d48..fc474f288 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 3672b695d..dd6910dcd 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 2c56af6fd..6b1422011 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 fd215bd75..0eccf274b 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 6e1a05850..b9bc598e2 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 29e955fe4..a0b22054c 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 00ed91064..cc6c61462 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 da37a8cab..28b9c20ef 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 5eba34328..3c3de5caf 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 1820ed68e..4dbb340b4 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 cc0d5d8cd..81609b1d3 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 c30e549e6..eaf86a2fd 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 ce09d6c47..ba5e0042c 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 bb837257e..8e1b3ae6f 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 5409a7802..22f9ddb21 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 6a2a4bdb8..81d38fb0e 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 97ee3bba5..f4b015c76 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 b457d9569..b8d15f548 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 1f4572e21..63f3eda27 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 ed297ba2f..2a7831a90 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 9416cca02..c13775bd6 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 1ab865c20..95b330512 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 03732ec67..d2971214a 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 3537c181b..e75cc522a 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 a00de2ddc..8f52f3e16 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 0b5af9b0f..307d9acef 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 4def5dbb1..436c2e9c4 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 27c9ddd51..4c378e848 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 00912efee..1e9a611a1 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 823846012..056262698 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 24bd9509b..8bfe7ef61 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 8e88000d5..138fc1b2b 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 48c51b07f..987884c76 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 e3718e28a..4c65b739b 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 27135c505..0ce91862f 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 fc37351e3..b1610989b 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 9dc20bfc7..db8f0bce5 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 95c4c6dbb..8c5514edb 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 65a27f093..558b732a2 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 4d6a00aac..9d995a295 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 c215ed479..d0dfcb14a 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 b04b358c2..c2d6862c6 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 0e90321d1..dc7307b53 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 9cd5ffb07..c41e8ca1e 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 799b6ceea..092badccb 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 d90d1f80c..2520950b1 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 343c55c5c..cda39875c 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 d27cb2033..31a305fcd 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 7d2c42823..f1dd421ae 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 6a7de6c54..d99bd007a 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 5bef39437..85ef5c12e 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 20eb7bb6b..58bc42cce 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 aca4f0b2f..0a1ab7325 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 a12191697..3e1db09a9 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 aa16958f5..71cdcd945 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 a906dc994..d711343bb 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 fa10e05b4..eb3319c9c 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 9e7ed602d..465bab8e3 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 9d8eb6ec0..77cb3f3e8 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 e608bf9c4..3e888dcac 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 8809434a7..e3a61d262 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 20e0c06cc..96cd17e91 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 ec819f9d8..6319a9d47 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 016af44fa..b1ca610be 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 99f330009..3bf251ac5 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 5f4a1b177..cc4d61ab7 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 5d02ba7af..578e39ef2 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 bcfb91e6a..ed4c71b31 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 467a48c5b..86cc3c9f4 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 2230ea998..d2e76ded3 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 1647067f6..638771605 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 8f5b82015..130fb2a57 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 f5358bda1..80dd994f3 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 4b134f2aa..321c3b7bc 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 2a86953c4..bbd25f344 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 ee115fe6a..f4fc40a9f 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 890dffe18..5128d12e5 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 df4378167..6634d1213 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 2856e781d..74cdafeb0 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 ed77ed0ae..9d3abd288 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 81ba9adf8..8ccd7ab8d 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 647ada1c5..2c55cee7a 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 0f5fbe201..969a148ff 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 8228377f2..e1122839a 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 00750ed7a..6d6a3df5b 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 7be676c79..176370fd4 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 7346fdc3c..40332e139 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 c6d43ef02..bca39d547 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 51c9a7c92..fada5e2ae 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 4d3c6243a..e40220a45 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 f9548626a..fe9a1abac 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 2214878d4..dc3bb7e34 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 31ae8dfe9..beac1be39 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 21a558a96..19b2c3560 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 4d4c2af7a..7ea577663 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 159c6ef5a..bcf3b797a 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 a94bb6d3d..d915e7286 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 027eaf266..914938fbe 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 588617a31..0e8edd0b9 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 392baddb0..f5f6f7e4e 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 3d0c19e68..8f783c34a 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 1334b1792..c3ca02b07 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 48ba5b0bc..a04a744f9 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 a3c29b9da..6148a6de6 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 6379cc007..6764c0b85 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 9d23c582e..84d3187b3 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 0d7177829..4f2e249c7 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 9ae9cdd0a..150b5fae9 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 b458f5fa3..805a82826 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 d8a5ac8e3..72ccca8e1 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 f321f697e..ac9635fea 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 3f5dea395..51ce513dd 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 8b7c5bcc6..600dc71e9 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 66167ef68..4d471456a 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 b00d89d8b..87af683cb 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 e4b758f80..4d9648df6 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 e8d121fa0..385de2125 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 8de2af106..bceef34f1 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 ecc6bbda6..eb09a218e 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 790e3dd96..c172d80c0 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 030e04c5f..150c510e3 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 84a571c85..100432203 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 ccc66be65..8a0aee445 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 6f5a6ff72..82c48b51f 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 eeb361527..ecef6f04c 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 39b75fb80..ef9f96c91 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 53cb55ad5..94aa6cba3 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 9fb507b00..f5cf75b26 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 ebfc18f39..b98d3b5ae 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 e8e79d7d2..2c7a32deb 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 7bf4c7b8a..00fb954d2 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 f81743bfc..8bf4f7956 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 e8f87ef5a..7ebec2842 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 7ed43162d..09ae8965d 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 e68dba502..a79a3ee89 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 dd554c936..4111bda16 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 819c619e0..ad873d52e 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 656b30e31..adcba3ac4 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 d1b7f5505..f7057e90e 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 2b4d07e52..ef6bf372c 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 a9d157524..60c15aaac 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 d0ca3cf3b..7ff57db23 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 1aa9cc385..931e04159 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 797ef5bd2..720b81628 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 be1d31f7d..0311fe70a 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 ea8975564..3482384e6 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 616f9d765..4891d7f9f 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 250aff51d..934f8f159 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 154f7b61a..105ab0f60 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 903a5a62d..238a1a51e 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 59e96f6d1..8ecf269ac 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 2589e9272..444b51598 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 f40d70229..73a333c48 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 64a88fbae..0bbdd798a 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 9120e9684..362213bd6 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 d2278880e..4a00f8c59 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 98f334bb6..113700de3 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 47491a481..2a8045fde 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 d91821dc0..bd846b6de 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 820f9e0e2..2c8c8e1a2 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 d368eb225..202381efa 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 9dc83bcd9..fa411ebde 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 822247729..a23e65dae 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 c6bae5d91..e5280735d 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 1be6e0edb..21b860fb6 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 d15ebcc53..d43ff4712 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 d132cf8e4..319a81635 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 1b1948cc7..7a6ff7e2f 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 d78fd19ea..eb31a2e3e 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 de97e71a0..b0ce152ca 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 ac4f38dd1..fbee30f1a 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 6e5d49b09..c0bd89ac0 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 498acd5bf..7888bcad6 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 79d3ea708..bdbde030b 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 10d61d499..92f54f442 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 2e0ce1cf4..59dbe608f 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 f1022de37..e512dc4a2 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 db7a42c86..9fb0791e5 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 df6248aa3..05e82066a 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 dd3815792..0f60c16dc 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 bdbb7aec7..39eccf2c0 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 24d71396d..bc6364cf1 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 5e01f098d..84a60bc47 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 2268dd06a..7356efd9f 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 97cf122ed..7852f80a2 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 408f8607f..cbed71ba5 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 c103a3b3d..016cd606a 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 1ae665971..4bddcb863 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 e50900b78..d25111694 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 7c91d79b1..5a899b527 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 00cdb2d64..a30aad03c 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 3f14b6eff..503c0d6a8 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 a8b61cdbd..39214def4 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 47d97f71e..7106b2052 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 4a6513b2d..bb28bb343 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 4b89873c4..1e3da01b0 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 fa4c84f47..a1c2ed3c1 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 fb49cc930..43c63ca29 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 1c7ab3063..85b30b14b 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 8b62425b8..c6f1fc870 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 c75d2b362..8535cd8e5 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 50e5c7b7f..ffc79cbc9 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 4c1b8b9a1..b0cfd0f1a 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 d4f2866d1..f7371941b 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 cf8554161..25ff09736 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 f713fb917..fa0ee3f79 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 161b01c9b..bcdb24cf0 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 846043e60..ba775cf52 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 d8bd520fc..3d0d4f416 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 0d8d21491..f9c054428 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 7950b02e3..631189ff2 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 3785598f5..e9c0ffb5f 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 dd1073c05..9bc69b962 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 15b799922..f2f67b361 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 da503e223..2925f71b3 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 17651c4e8..fbc58e634 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 6804c3f00..08c0ffc71 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 da5698220..0b2fb5972 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 1ff5bcef8..419946f78 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 42b9ec323..ba118cd69 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 30f9c1f10..65e367b65 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 fb840f80d..dfa848c10 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 9865dcaef..fbaa63325 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 ddb760788..4c5b92532 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 4f6a2216d..82eb967d0 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 106e98f2c..5ef12b3c7 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 db885d4b2..71f87a1ca 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 a8b76f29d..25db40303 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 3215ad6b5..c1f6dd02a 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 7b360ccc7..9768326c6 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 43eb04b9c..3ec1936fe 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 af87a242d..8dcb1dbd6 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 fbe658d93..2283b8954 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 f22933da8..3b456472c 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 c1f18a5ef..396030705 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 9bc564fd2..1b8a35344 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 760eee6f1..81dc154aa 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 dfcdf7a29..043026b06 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 107b1d4e8..bf0023b2a 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 edcd0ef62..745ae472c 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 d669b0922..46343345e 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 e2820d110..291afcdbe 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 939081767..b34b96c23 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 ec9f8ef51..aa6755bbe 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 114005f79..8145d280d 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 531a5ce0c..611b35c91 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 8e1c4b739..b7a0017a1 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 586e8e923..05e3e185e 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 14ca2f3b8..a90fd5a9b 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 5fe9753f8..64b6a5429 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 f95fccfbd..1745c4cf0 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 f0cff504f..67b11dfbd 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 7b4f329ba..5a4dec77c 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 c5be2b3cf..1fe54611f 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 4f75e6dda..7b56f68f2 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 8ec965d92..ee3baf8ec 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 343829a4a..81cf054cf 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 19797e71b..d8f9ff444 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 26c17142c..233bfe857 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 ac263b986..01db39cd7 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 6375efd13..0248065a8 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 65fe379da..55644e621 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 44ab7220a..dc727aafc 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 7b61d91af..cd559e8fb 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 903e507ec..d05d310e0 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 7b805f20c..c0eadb061 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 d71f27040..4a2364175 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 3310f4c11..b0ad7d79d 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 373468a48..954362812 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 8e3e32fa6..33dcd9f64 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 583549730..fbac7e242 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 ab2020fc8..955187d60 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 7bcdf777c..82d4da9c3 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 886ca1506..c632dac34 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 80dbe208e..9d90c6ea5 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 28553efad..6d2232004 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 2611be7e2..152ccf30c 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 4fac22532..655f2a4a6 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 4e6dc1738..3b726b6c4 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 2890369a5..cde978ca1 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 5f960bbcf..69576c993 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 cec15ef5c..d32f10fb0 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 18c7f4e2d..6f74c254e 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 817cbcf2b..3bf8f0d8c 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 149c11442..bd3e7fff9 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 030067388..2fe6854bd 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 df56c337b..a8ca3e93d 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 4d5400d5b..2dab1dfe5 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 529cbf053..5cdc2f87a 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 fe1ea9bdf..857d6529c 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 891f936e3..15c67cbf1 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 0e563c930..1da52df19 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 866777ba2..89acc2aea 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 8b4639c42..add7c1f02 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 4f8fb88f2..0c87f9a21 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 f0e7d3f08..c380a9b54 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 495081957..bb654863d 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 ad460da8a..28b3f4249 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 66cc880be..7af5693a0 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 0a8eda56c..e047ca2e5 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 4fc9c78a3..53a2fe78c 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 cf31d8e07..c31127081 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 45bd25112..de9772215 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 bb49b8e23..d8e47adc5 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 30806a48e..aefce8619 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 78e2ec76c..7393c8a2e 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 ab79e5bfc..fafacabd3 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 01df2461e..bf283c411 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 45b11fa3d..542e9f493 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 ea34b482d..2d27ea559 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 e58c787af..4a23eb18e 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 75b61f3f2..043e6fdb5 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 53c25bc13..c9c096eee 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 2686f3f25..58d3d9601 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 de0bc88fe..90a78d90c 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 78bdadb7f..ffba3cd90 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 3a6c66090..c5db49e48 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 da1bfaf47..5658c9228 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 8cbc21fad..450abcdf5 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 e7c8d33f5..e19b525b0 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 0a887dd02..0fed41e3c 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 8f84fdbfa..99177abde 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 e44e04889..b253b8577 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 ae9e23fcd..0309d6423 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 434f6a2e3..1a9f3f341 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 79b65feff..90ed5147e 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 a128d7cf1..1f15284bb 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 8e12c020b..d02dbf372 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 556e120fe..976c5b528 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 c15d738ee..9d8a555c0 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 e14da20ad..9595a0d47 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 06eefbba9..85ce5a08b 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 07c41305a..bf92eab30 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 928f39686..736bdd68f 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 8b53a8c6a..27eefffe1 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 6e1a46446..e24ad2d8a 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 6cf1f8fb9..94d5dd0c7 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 450785bea..2fa7a53d2 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 e5a8fad6b..576f585a4 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 23c6ce19c..60d426f1b 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 d3d960401..c40270e69 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 33c01103d..8fe39a17e 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 9ac807b7f..790373d01 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 a99367760..36eee526f 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 d8dd66952..e73e840ec 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 ca791bf64..5a21433e3 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 f1c596ab3..4fe995597 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 685b5d3e8..2fe5a5d0c 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 43737f3a9..2e11ab4e7 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 58939bcbc..43df23992 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 f0084e1e7..4ebf1e97e 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 73001c811..082aaf120 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 462a06031..7b49bda13 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 e3d9ac556..e2ae2de61 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 2e129453c..09d6b12cc 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 1ade93f89..153403d90 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 b60e40722..51543717f 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 1d0674c24..891ddf635 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 273b6bf92..c7a6d0b12 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 bb6fe7b9f..1b4fe1e1a 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 078a8e1bc..249e2e1b4 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 7cde4d256..dd3a42d26 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 bfd8524ab..c4179cec9 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 7ce0e0b13..b278b4397 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 2337d5e94..2f9e74a62 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 df072d944..ce1966e7b 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 424ea205d..213891c53 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 97be96839..bc983d752 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 291649036..a07fbde51 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 a47e0b656..97b835dea 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 2940b9180..472001dc7 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 b62d3c059..53d6bb6c9 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 e67b6c8b0..950826200 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 2dc9ae4fb..6104fa5ac 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 309831225..ec937b236 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 720023106..22e98a3a1 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 c2fdf4a36..677a14886 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 ea82c01e3..82aa813ff 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 ee923ca60..9eab4f204 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 d7c4344f0..0e58b69f7 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 74b56ae04..6fc8df202 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 b08af7a8e..203e8bcdb 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 a1b0ce4f2..1c90a5f27 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 bc98a87d1..787fb5bd4 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 d4eb504be..67b8b4727 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 98039353b..552f1a655 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 92b7995d6..77627165f 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 72091e7fe..952445b12 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 9df909fd1..d5cc635eb 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 4c2765d46..b4a28cffa 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 efb939050..62ea0eac5 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 b425671bd..6bc10bff1 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 ff547496a..bbd9a2b8f 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 7c976fb87..8e03397d7 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 58936fdcf..4b2f3b6d1 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 7fd893b87..be56c6135 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 0779b1d63..d75cd8d95 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 072c2fc66..167494fff 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 b0107d900..33a4579be 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 e0aee7815..8616e7d6d 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 deea2260c..27a7c48ea 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 53695fc2e..04b8d02be 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 5676547bf..b2e219d03 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 b51414fff..e6728f06e 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 02f28d400..6b567401f 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 8ef6cb061..701a30b68 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 62ede77ae..280cb44ac 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 d614a11bb..c0f0cafe5 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 3681be384..4f116b637 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 c4525c137..7c2707007 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 459ac51da..8ec330e16 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 90615ff4f..45270c925 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 20a7fe0f6..9608a17a1 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 757337288..787576b2d 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 fd0f53fe5..9d3eb0cf7 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 406352474..0a088a559 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 c074ab099..5b6e95d31 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 13bd22e37..6adf703b2 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 13583a218..fd9737ec3 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 9a42abac2..3dac3a39f 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 d966db121..0630eaa5e 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 109002b9c..f1ab06031 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 4c3e4030c..82d384b39 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 f7ad15e36..e47b2174e 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 c25af9d5b..67a67bbc8 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 ffe80cc19..c9a74d9b8 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 09b2b99f5..a65722e95 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 f89afea7e..ca24c7974 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 2ab4125d3..5c237c76f 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 2e6adf969..ffc73a663 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 67d29c867..99c53dfcd 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 228a8cb73..292b32a2c 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 6715736be..52645051d 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 9d27d869e..2a5ae1d9e 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 2521e4d00..6a1633882 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 d1700523f..55c781d81 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 94002b449..e2d460500 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 9a66e765c..903d2a449 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 bd408eaa3..7c9b8ac3f 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 11a1921c3..489c255f2 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 d02cde57c..18c418e57 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 6f6ce29ec..35cb666ab 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 20547b31d..0a1c8ddf1 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 2f03b039f..06955fa61 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 7db008682..398e34e0b 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 18ca4259d..a7b1f85dc 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 b7f3c6a92..da3fb47ef 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 7c2d455b1..4bcbdd3a4 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 9ad2a42d9..c5b04cd62 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 6709cdb82..80e64bb33 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 1da2b3adf..cf5dfac1b 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 20cb560d0..04fc79fa2 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 ecbe1a934..2ad2f5aa4 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 c41fef0c2..48822a999 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 4b91377a1..8095c0761 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 349a34131..118528867 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 c16683350..9b3a98994 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 3f90238e4..36a035514 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 b00a7d191..c7917df8b 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 964376023..d4410ad91 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 79bbc6c18..dd77b0367 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 1103fb091..45bde5e8f 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 83beb889c..906a628d4 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 ca9d6ba87..910f08bc0 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 347896d88..2d61c4a1a 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 8dcbe625e..db283b70b 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 1c4bc0def..3260c5cc8 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 2001fb851..1f50775cd 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 88785e188..56f269495 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 8fcd993c7..dad3ca9ce 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 a52c12924..cbff5a078 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 791aa1e91..eca97a90e 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 d030e13a4..374fe4520 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 be8e8f0f7..1c0713735 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 2660d4ebd..38a7287ca 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 559e0b9a7..c3bd577bd 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 00ca98f09..21904855c 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 59e87ddb9..8c7791c2d 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 93735fbab..4e81c0e7c 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 72a624b73..d07261831 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 1183d06d3..1db8641dd 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 7c26feab7..dde8be4dc 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 47d07445c..dcfd0769f 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 928cdb180..50b4cb2fc 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 ce3ebafdf..93e1782e0 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 35f3cad7c..b6571a55e 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 846a0b17c..e148f7c6c 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 0c5ec1c1c..0573db94c 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 6dd8d19d8..05a9792be 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 44ad3b84e..f889f6d2f 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 038dca910..dfbeb6dc3 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 5ed03c1a6..3d6fbf7d9 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 f7bb93277..ba82ba7e0 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 384c3d1d0..037c34f0f 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 aa6b39d1a..c140b91cb 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 144d769b7..c5b7f11c8 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 223ca94ad..ecf691d84 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 97a58d791..95b9d1097 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 d98192eb6..391e47a22 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 084c7111d..fc8fc7402 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 b3fd6d466..ec31a3c2a 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 c37f63dab..601d941f8 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 25dd0a552..ca08976a7 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 b8321a7aa..e070fd177 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 355f02e30..ad2cdcaaf 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 db3a438c4..386a6be30 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 4492e22d2..f020fc180 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 c4a8eafa6..7ccb509fa 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 e95cb741f..2df85f52f 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 0745069a2..2f7c2fa28 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 85de1a87e..81fefb566 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 4defbba44..072961291 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 236d60649..a108107bc 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 5f5b4a014..466c3fbf5 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 8c2443af7..db972148c 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 d717b4d87..d580a0d3a 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 b09bc28d6..bb49bee09 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 e679e58bf..435adab1e 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 e2eee40b8..3be472a9b 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 8a3680599..3b7c07cef 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 1fc850ac8..bd72b2e4f 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 f1c368012..487edd66a 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 62f403eb7..4fa2f98ca 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 c67cb2a98..1a113ec9e 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 144c14e7c..c1477388e 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 799ed0dfb..42f7d12a2 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 5bccb3527..1949fc3d1 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 0cd28fb25..7ba71d554 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 8076777ed..793bcd029 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 8c45a148f..0e77216b1 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 2781bd569..d99d9f78b 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 49f4dc8ce..ed9d9e90f 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 8770f3ebc..d1e88b7c0 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 af73dce13..7bc741528 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 dbf88255c..c16b7294b 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 976361d91..01d9458ca 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 c6266e221..dea1c0c37 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 fcbf1a67c..113b725b4 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 b9bb5617d..6c063ad32 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 1f5a28385..a6f13c06a 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 3bdce914b..90ec02088 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 a86d12c01..465f2b563 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 72137658e..89e7bf9ec 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 fe7a5b38a..9d3151d83 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 4823b921c..699461f2d 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 28a6b6fd8..8ee331924 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 2cc302812..f899aa478 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 0022dcaf6..90ac1a778 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 26748064b..973a645a6 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 aa83d6a11..fb7a9c4bb 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 7ffe30adf..9ed528456 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 6eaacb5db..697d86d3c 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 60c216e8d..aad6685ad 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 e9d731635..b469eca77 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 98d7a9f49..c7ed7f44c 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 474d20e9f..d0b464eef 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 769cbfa2f..92e675211 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 71b97c884..a7443fa6e 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 0cb6e2067..9f9422f75 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 b35f2f91b..1f9f597e0 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 50f21d2e5..22bd21875 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 e780da33f..d066c627d 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 6e5c68ae8..239da5eb5 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 1a8228d8a..0b84df30d 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 6343d73ea..223620585 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 4a73c3c19..d0630420a 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 3c4934df0..f313ad0fc 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 682517e77..e2a81dd41 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 e86eab24d..623e02a3f 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 925ebf601..276107348 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 b78516ebb..008bdffe4 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 49963f3f9..78977dd35 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 66cd8236a..f4293402b 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 cbcf86fc2..27f35d883 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 145a2a913..6503dc7a1 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 317dc17b4..61fdcb317 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 2a477b13f..e8b137b57 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 222033ec7..7e9e0f575 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 0070d851b..6bb0c2023 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 88b6b932c..120ad1281 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 96ac93c2c..30194a22b 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 de8cb3b15..93d41ee7b 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 6ca6c70d8..b17bede49 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 5cad040b1..3dc0d710b 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 6e517c1de..e77d453e6 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 5cf0d5aad..23712a9a7 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 5268061d9..5a2c43790 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 a3b2b5e00..24dea8d43 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 dbc566435..463812c28 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 4857d74bc..32b84012d 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 70b878e15..7eefef7fa 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 132d0a7de..03da77fef 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 1ceb3d2ef..30bee9972 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 aa1b545b6..e0f6efe6d 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 fbc969321..b4d3e6e93 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 75e644252..a75e60016 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 8b0032d50..44531dd30 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 f4d2e9ca4..b0d698558 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 41b389119..1e64c4d43 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 32a2600ec..ce64ee0b2 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 36d41e2c9..80702113c 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 572036ac6..a143729c9 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 71e647294..b7e9964f2 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 e69d004b1..7830e8e2e 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 3ebe7a87a..492e941f2 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 89f17e300..f0cf0b056 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 9bfdbf1ec..256e72106 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 222b0bddc..701ba1559 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 08a4e4ffa..9879920d2 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 1d09223a8..9ec93ea1d 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 758795af0..a8642ca65 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 5f747ba9b..e7b92552a 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 eb7ae5622..899d9512f 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 c04262402..29b60bf9a 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 6e7f1eea0..5be801128 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 2d912f3b8..8e7b3cc0c 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 ad8cce97e..1a9525f31 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 731a92a8f..c74d50fbd 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 3591f928e..e95167b04 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 197140de4..2289b4cde 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 f6bb5b8f0..bb39a2cf3 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 bcbcc306c..aa332a7cf 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 d8b060d70..7a263b5c9 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 dc1c7aea1..2715f5dce 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 de1ff62ff..2c1f295e5 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 03638fffe..00ad13bcf 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 071f3089f..1600654e4 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 1c9c1bb58..1efae1fd7 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 c1202e3ea..a0926a0c5 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 b099ae3c9..015cc593e 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 2a715c431..6be64558d 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 44303f79b..d239fb346 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 2304f01ca..ea49df73f 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 973a15b0d..5893954a5 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 77b104542..af9329962 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 58a310b8f..03f06faac 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 3be3b5730..45a4a59a8 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 283e2e51f..fd5bbb0a6 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 3234b3b3a..ef7ff3e0e 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 b0a18af14..05b75dbe8 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 c6d4f733c..0ae806b57 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 50a144047..bd33e12ae 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 dfda6b21f..2fd20f126 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 361dc36f5..cf43940f3 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 62f224d1e..4e3010d5f 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 20d2ec3dd..4cd3f5ff1 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 7419ffd5e..5458510ec 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 a61bcec93..b6b9a58fa 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 f222fc823..c59a8af2f 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 a1e81db29..bb0213438 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 702c2e6b2..9c6cb98bf 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 cf3d58aac..6faef3adc 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 68602d596..4aea505d9 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 f26683f15..c83a2e389 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 229a441be..ad6d22232 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 50b543922..a23af116b 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 942083b51..886050e60 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 a77ca4fa9..2ccc5a3e7 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 8ca911c28..3673ca778 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 2a19637a1..559568de1 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 27cea3933..0f58b1cd2 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 9e069b907..58f9caa3e 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 97ace0490..ac67dd72b 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 6ac921d47..0ede7964d 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 e2f9a04a9..b9998da17 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 8f572b41a..1822ccc83 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 d0569c362..5cb1eb9e4 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 67f4a2d0e..26417683e 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 89490b48e..1bb1a9493 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 b6bca21fe..82bebe3d4 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 ff6128eb0..d07adeaf8 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 a30abbbec..71bfc4a01 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 e9449d679..63e061678 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 deda8767c..cd480561d 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 f2ffdc93d..643529150 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 198de9553..5d11627c4 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 f33450d0e..64a289e80 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 6791ab82f..6193bd95c 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 cf9f2abf2..efded911c 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 1b1bc9a3a..c07eaf933 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 28d8bc159..d82986804 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 28abf116a..c7bc5dbb8 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 db262eb6e..711403fec 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 678381255..4312ac202 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 e1a9b17c7..da24154e6 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 fcc08ae29..d62d3f958 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 5232ae39d..4c5aff3bb 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 b89632329..13e3255dd 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 59186ee3b..1050c9619 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 12a5d48e6..06a04bf9a 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 8f37d0d1b..c9d5d6962 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 a285c58eb..03fbc1eab 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 c17e8154f..6db22c7aa 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 d15c7271b..0b43d5245 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 86f8e6e34..699716dc5 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 63761e865..da0598d21 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 89f933ed5..a55a5ee23 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 225c90a41..7125d62dd 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 cd076e2b7..521560428 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 8e613d5e2..7d410726c 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 f16d835d5..3657e66d0 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 e247e9f8a..ba09ab1b1 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 dcba5b569..fbf071504 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 65dc160aa..8f1ebc8a7 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 5f507c4b9..7a81f3d1b 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 9aa519a86..3f82319a6 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 bda69bbcb..acf1b8557 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 22a03b189..931291f0b 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 ddf71d935..2072aa1ed 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 1aa463eeb..e3f1a6c6d 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 ef086498b..6f6ee28ae 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 aaf0c43d6..a0c706773 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 dd4e2404b..2b5195bcf 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 097fef3fd..988bcd9ee 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 bc37898d2..0abfae337 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 8cee60eef..50d8937f3 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 9a49c4b65..1f2c0ac3c 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 c76f5cab5..4489b0553 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 9c7b63e9a..36fab1644 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 4d932d7b4..78ee36be1 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 07b31a59e..2fe6758c5 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 c79752c4e..2e55c3cde 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 223360144..e29271892 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 cca1d1f85..c6cf8b6cd 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 49cd0a265..10a86b4a1 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 501203e7d..2b032fa41 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 bcd689015..9bec38dcd 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 87f763885..11bc7e57d 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 970713a71..42c7a0441 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 69fdf2508..cf15006bf 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 8b9c47ea6..b97876183 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 315087a28..b81f100c6 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 37bfeb955..e056bd064 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 15bc962a8..ad67d883c 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 5c74bbf26..8bff908f4 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 2c485bfec..5983260f8 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 df706a5a0..c9dc14381 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 4452d43f0..2052988e4 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 7bc655886..2caf7b4c9 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 b4ba190eb..91d37974e 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 77f823cef..25efda1e9 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 e6cedb517..e3ce19a1e 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 02d78a0cb..1781252db 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 e2fdf61fb..de337404c 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 a80a99afd..d1b25c71e 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 53f056a75..2a197675f 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 166da48f8..b76689c57 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 047bce900..7fcafd2c0 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 4e9a3eb21..476f05ec0 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 c04f27083..def998025 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 3d37f2251..7c1508aaa 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 6a56833bb..2464e741a 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 9a624769c..0946c01d5 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 10c0e1346..7c344bd42 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 4ed32a3f8..9cc99425a 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 672a31087..cf70190b9 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 b4d10225e..358b98f1e 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 2fa869bd3..66c0974a5 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 6ea4a9d4d..0b6bcb56f 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 4a47558d7..c0aa2cc66 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 7993f0a90..f7c4a291e 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 da514efd2..17ace4a36 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 972dcf48c..5bc141660 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 c69c47bce..4f439041d 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 5780ef026..4501480ac 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 7bfe8aecf..bdb199eec 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 cff57af24..d7f41d16f 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 2caba15ba..4edb5c7fd 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 a80633dec..8500e8fd3 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 a3ad44e5f..160938742 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 4b7eb3bc8..9e032e4c4 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 f7c855911..41bb2f678 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 0f53111c9..1f152c399 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 18226d933..583f6d78f 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 4c0ebdaf8..4e3768ec7 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 d312c59ab..427b477ad 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 cd136fa1c..c7c331e96 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 c70adf09e..ed90db308 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 23470a636..1b4228227 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 98865d68c..cac27869a 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 ad43a0329..e86ccb5f1 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 15e552ae8..c054eb22f 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 0552e97d3..dcef7af68 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 0893daaa9..8f94b72e2 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 2a32f711a..59c2d9d92 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 48a4114b0..731bb3bfb 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 f84f51970..c7afb8a5a 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 5e2e88824..b6278d704 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 e705845fe..d8332e8f6 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 007b36b18..fa89c6ec3 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 f2509a7f3..5d106115e 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 e0e88996a..c8db6bc6a 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 2eddc0f94..a1d2b34e0 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 98877a530..04e2eb66e 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 4a8ce60af..22078b487 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 42a8c627e..2d5c3c3b4 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 67920907e..1a4ee044e 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 b930648d5..2f6576e2b 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 aebca8e40..ad4d43efc 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 3b7ecee5b..fac5a0d87 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 3e7a57626..ad8dea731 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 18b5452f1..10182fb96 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 cfd803119..5bd29c462 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 cb3804a3a..324e3e4f1 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 57137a67d..b84a5ca61 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 7f6fb6a9a..18cc11c4d 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 0a8e0e84b..27cbd5f03 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 b720b09fd..09c5ec15c 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 0e80b7ff7..c36b22a2d 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 153537078..abfd136ff 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 e4dd44d7e..49c9f57ba 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 01072b17f..14f9ed47a 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 ab9ef48fa..d215c9c60 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 648544ba2..f524bf093 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 436f906a9..ed23dd71d 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 887533124..690e4d74f 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 5918b39eb..cee80035f 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 a28cee918..57297a939 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 c1da01331..9b4300ece 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 eb712635e..0334aae3b 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 45270399c..cd631bf45 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 e6d329c1f..8493415f6 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 c9382484d..a5ed062a0 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 35d6b6236..a2d13a4af 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 13b41f93a..3b5177a2e 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 06264e602..9d1dafc66 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 c77ed6d1a..2d7409399 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 5a1fd241c..ccdaa10f1 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 8366d9c12..67a453b0a 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 00de617d8..c94c85659 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 e7285fd57..2c8a17101 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 23614d205..9b79add9c 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 c0cf0b01b..1f181e2c2 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 664da140c..31da1732b 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 aa8f0b31f..a38bf4539 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 7909590a0..0e80f24d9 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 1404edc3e..6f32f34c8 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 1f2da6e89..4d8f80065 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 494d894f8..0e8026a37 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 c8c692cc1..e9bfb89e2 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 be628a8b7..97c6bdec0 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 ba754bd83..62445dcde 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 bcd9162e7..7c58f6a50 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 fbd412ab6..bf56ab48a 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 59683c505..065c128a4 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 ac9ebfa4a..75b9a0574 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 39bb93d09..ca528f985 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 921a8e52a..b7a85c736 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 22585f334..7dea5198f 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 e6e6eca7a..1b5b5b622 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 166ef70e4..c0b8e5cbe 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 082fc1afc..c49e2b76c 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 f92d31c4e..b4b54dc09 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 00480806d..4e2e692d8 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 18502d2b8..0e69ffdee 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 0e4c6521e..f830c557b 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 8e5d8b9df..e0cebebeb 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 082e0307b..8a5d0e9b3 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 09e959a1f..5bc6c534a 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 51197dfb6..a99ddede2 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 02c729a11..973658495 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 41c60bbcc..fbc8e649a 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 86b653dcc..5ab13013d 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 7bd60af3e..afac5bd7f 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 4b83dde23..965db5c7f 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 b49d81f41..a4f030347 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 82499032b..790ec7710 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 7e12df27e..40d6ec035 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 aec14863f..97c79c4bf 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 b2021ded8..adad4d856 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 3cad872da..ade1e3ca9 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 9951fc2e5..98b0cd0f2 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 4007724f2..56dce99c9 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 a4b0469a5..3aad9282f 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 a06ecebb8..f95232212 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 c5f479b1f..60b47a72f 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 ba3c21a84..233f5cfa9 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 0acc5def8..808d81983 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 1a7a2d608..e2e660584 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 4cd09150e..4c8ca589e 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 0d20d8f44..1d442aad3 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 6ffbe611c..786f60dd9 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 a15395f4d..46ef0b497 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 382ee616f..e5305e526 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 ac244a68d..d74356242 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 9c9755a60..9d9e2b373 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 f6e13d6e5..2dd339b72 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 0f1e788d7..5d3bbd04a 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 9acfafdee..6af4fa807 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 f12e37c94..91a5566c6 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 5991726bd..215c77e31 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 0f159be75..f666a6aba 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 7025f8346..e4d2276f1 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 cd32d246d..22be4af1d 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 4dddf4101..873c41d1a 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 723418b9a..4b4a0e969 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 51791543f..9eb526e79 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 1760cbd18..6ebb1dcbd 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 8f4255ccd..99d46b9ce 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 205c40c67..7f01fde90 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 6d371befe..3dcae4e3d 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 5a4b9269a..1dec12a47 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 811155792..453b04fb7 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 f83401e88..207bf28fb 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 ad6142b49..ec684b10a 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 96c347421..fe30c2009 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 06e1ca3ba..38d07f990 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 ba86f29fd..5d5eb5038 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 4d73c72b3..39ef7f62e 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 38ca5a52e..76620ebc6 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 16458ec42..5fef9bc4c 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 c20858518..8d5019c84 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 560c92ead..0fd096e68 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 29cbeaa69..04ad5eefd 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 d6742bced..250945615 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 a86731755..ffad8653b 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 8f96b6e8e..e3e2840c3 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 a40551098..611ce5faa 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 4616fdbc3..b0012a0bb 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 19e770d8c..51202573a 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 b07731125..9cfe8e0b5 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 ae26f90f6..29ea44ccc 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 2f148f74f..9a0653a7c 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 dccca0225..a0639dc59 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 caf083a7f..0884455f6 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 232e11d08..b52d3257a 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 59f8d891f..34dc8904d 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 4dcddd505..2ece6e598 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 917273b9b..1d4f64743 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 0b30c3daa..91b392329 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 f1cf19d86..165f01159 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 27ae5804b..1fa437aeb 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 8a50f08b6..7426b7a9c 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 f3fc112f3..ec56fe77b 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 310f62ed9..d2b613f39 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 4d433c5ef..57e5493c5 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 c3ce3ecfe..dd64ef426 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 f69bf2e5b..c85e48943 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 b658dd526..80f2577e0 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 34d9cce5c..87f4c8d09 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 176f1d1a2..17954f29c 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 80868c395..4de44310e 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 eab75f975..7c3d1e748 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 115ba9e07..3cb88255f 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 0bf754e18..e8fc8b2b6 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 9586d2381..e32eca1a7 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 daca850df..0a9757da3 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 11d638c05..9b0f53933 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 f40a3ce55..e16c8852c 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 0cdf5bc1f..c4e48e00b 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 c758a1eb1..6f5318a42 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 2046f2b44..f08b3b7ce 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 133dafe0c..77be1b7d0 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 305b48bdc..a105b9bfc 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 e8f02e5ee..d05488c89 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 0231a95f5..96c203caf 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 8d4af8b36..064a7d137 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 7bec01328..011730863 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 3c00df482..b96e0ad49 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 1fb5b0f78..b50904e1b 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 29ed31057..db07551ef 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 174db7bb0..2531f1377 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 d2fb6eac2..73e3087b6 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 0471c1bf1..551059c43 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 752e551bd..1c220d820 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 9053568e5..7dd71f36b 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 72d0f5bf9..8ac7b4d60 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 94004bde6..1634e6c5f 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 4cfd49501..89f32ef0d 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 7c1c31217..3035bbb75 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 2f715a712..b72aa9244 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 6ae9217b6..042b370d6 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 e757f220d..97647f174 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 73e30bfda..c24704141 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 bd645b9fe..ab617ca4d 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 6230ad140..8e47702be 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 f43df25e0..3b79014ec 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 d2ecf157e..d1ca8629b 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 50126ac64..77f622b4d 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 0a17599d6..46a86b470 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 6758be153..375ac9df1 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 67875b649..c34993281 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 d5df9a1d2..4569caf60 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 54812e1b6..d6f8dce6b 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 a6dfd9560..e56ce3ba0 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 2b6299fe9..ad504d611 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 dae9303ad..496930f28 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 17facfc42..cf6ed741d 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 2be32a7d4..7b86199cd 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 2192ea7c9..15c3dfb42 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 7b6004611..679d2e65b 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 75739384e..3b04c8223 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 c3ec546c9..77ebcf652 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 c9141d3fc..e0d600fcf 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 ce2420351..5d3a33e4d 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 191d4cb17..6e8653648 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 b5258f5a9..9954183f1 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 60ab5ac8c..a362dca9f 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 30ad6bf36..55084f35e 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 5ffb1dc44..1d5752fbe 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 6d29a2ada..d382048f1 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 f7f8498b7..17404f619 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 dd5068fc6..03b49245e 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 5c6b9c54e..28b1690d4 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 6ebc442aa..967eab965 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 487d9913a..65d41b9a4 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 67e37a7e0..223e1f034 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 658731859..4cfcf6dde 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 3d3a9dea0..62385cf08 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 718ef659d..4aa664e60 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 c92215c08..eb9f64771 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 c52c27b70..41e82dde6 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 46b9db41f..d643fa2d2 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 ad1768fc6..1ad1dbb96 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 a9d0c1555..94aa2a2d5 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 485c998a7..177b3749b 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 8aa491966..6e3421632 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 f7cfd338b..8933bdf23 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 f4b5a2a87..8c8986a0e 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 199d0d8e8..bd96a0553 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 296027978..087e38d42 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 2336d4813..ee5d29ba0 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 d14c8a2ca..9502c0117 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 2520a6398..fb0783374 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 b48208a07..0f2fde09f 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 bce2a9005..085625841 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 c38df9437..e93c13043 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 e4cfe345b..61992386e 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 241c73dea..0f4649de8 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 a1b6a4272..a3b5009cf 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 47946b762..174ef448c 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 69b547443..d9a06c5f9 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 6f408946d..91c6e6754 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 f2e525c92..eb8206a24 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 0801b1e2c..9421248e5 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 68a21a1aa..a743d0c58 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 e1d573d67..a5de690df 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 b8df15eeb..afbc2f7fa 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 7afe23776..b85aedbcb 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 80b8cd5b1..0bbe90ade 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 10fde6e8e..06409cee2 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 82a9d02a3..64fa64507 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 3f9261eee..cfc1bead2 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 865932899..673b1422e 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 58f526a32..c6ef75f01 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 949aa86b4..8340c15c2 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 25473cde0..f7d1b90aa 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 5270244e0..1e848ea20 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 d859b9333..d5ac8dc33 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 000000000..5b655dbe3 --- /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 2b90f5a83..26f2de9ca 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 38f8eef69..1439acd89 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 6610c76c8..e3b6e31d2 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 000000000..845f5ffc6 --- /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 000000000..400526014 --- /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 256c24b9e..0af5dc026 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 000000000..7261bf03c --- /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 c8f72296e..9a19ab36f 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 1d351caf5..7836ae52e 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 5cfdca334..746ad5fd2 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 a43c1fb39..942102abc 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 71d6d8ddd..cc02005ae 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 6e7afd632..9e909b39f 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 24bac40e4..e72ca3568 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 f029f44a2..31b648360 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 49e564297..f03d449ae 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 fe8742408..194e9fae0 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 a8a521495..1b4ca8657 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 684644036..9b0fcb0fc 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 000000000..eebbdfb35 --- /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 + ] + } + } + } +}