From 17c61ecf17f460f13007c993178c228f10160e0c Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 12:18:37 +0000 Subject: [PATCH 01/12] Bring Electric Advantage to Minecraft 1.16.5 --- .github/workflows/ci.yml | 47 ++++-- .github/workflows/codeql-analysis.yml | 33 ++-- .github/workflows/validate-gradle-build.yml | 4 +- CHANGELOG.txt | 11 ++ README.md | 122 +++++++++------ build.gradle | 65 ++++---- docs/NATIVE116.md | 114 ++++++++++++++ gradle.properties | 42 ++--- .../electricadvantage/ElectricAdvantage.java | 6 +- .../blocks/ElectricScaffoldBlock.java | 8 +- .../mc/electricadvantage/blocks/Ore.java | 18 +-- .../blocks/PumpPipeBlock.java | 23 ++- .../compat/BaseMetalsCompat.java | 4 +- .../entities/HydroturbineEntity.java | 44 +++--- .../graphics/BufferedQuads.java | 10 +- .../graphics/ClientRegistration.java | 2 +- .../graphics/ElectricRenderTypes.java | 12 +- .../graphics/HydroturbineRenderer.java | 12 +- .../graphics/LaserDrillRenderer.java | 10 +- .../graphics/LaserTurretRenderer.java | 10 +- .../electricadvantage/gui/ArcFurnaceGUI.java | 4 +- .../electricadvantage/gui/FabricatorGUI.java | 4 +- .../mc/electricadvantage/gui/OvenGUI.java | 4 +- .../mc/electricadvantage/init/Blocks.java | 2 +- .../mc/electricadvantage/init/Entities.java | 6 +- .../mc/electricadvantage/init/Items.java | 2 +- .../electricadvantage/items/BatteryItem.java | 12 +- .../machines/ElectricBatteryArrayBlock.java | 2 +- .../ElectricBatteryArrayTileEntity.java | 2 +- .../machines/ElectricCrusherBlock.java | 2 +- .../machines/ElectricCrusherTileEntity.java | 10 +- .../machines/ElectricDrillBlock.java | 60 +++---- .../machines/ElectricDrillTileEntity.java | 120 +++++++------- .../machines/ElectricFabricatorBlock.java | 2 +- .../ElectricFabricatorTileEntity.java | 6 +- .../machines/ElectricFurnaceBlock.java | 2 +- .../machines/ElectricFurnaceTileEntity.java | 2 +- .../machines/ElectricGeneratorBlock.java | 34 ++-- .../machines/ElectricGeneratorTileEntity.java | 32 ++-- .../machines/ElectricMachineBlock.java | 44 +++--- .../machines/ElectricMachineTileEntity.java | 74 ++++----- .../machines/ElectricOvenBlock.java | 2 +- .../machines/ElectricOvenTileEntity.java | 4 +- .../machines/ElectricPumpBlock.java | 18 +-- .../machines/ElectricPumpTileEntity.java | 38 ++--- .../machines/ElectricStillBlock.java | 2 +- .../machines/ElectricStillTileEntity.java | 6 +- .../machines/GrowthChamberBlock.java | 2 +- .../GrowthChamberControllerBlock.java | 10 +- .../GrowthChamberControllerTileEntity.java | 20 +-- .../machines/GrowthChamberTileEntity.java | 14 +- .../machines/HydroelectricGeneratorBlock.java | 8 +- .../HydroelectricGeneratorTileEntity.java | 12 +- .../electricadvantage/machines/LEDBlock.java | 22 +-- .../machines/LEDTileEntity.java | 6 +- .../machines/LaserTurretBlock.java | 16 +- .../machines/LaserTurretTileEntity.java | 140 ++++++++--------- .../machines/PhotovoltaicGeneratorBlock.java | 14 +- .../PhotovoltaicGeneratorTileEntity.java | 6 +- .../machines/PlasticRefineryBlock.java | 2 +- .../machines/PlasticRefineryTileEntity.java | 4 +- .../SteamPoweredElectricGeneratorBlock.java | 2 +- ...eamPoweredElectricGeneratorTileEntity.java | 4 +- .../migration/ElectricLegacyMigrations.java | 10 +- .../recipe/RecipeConditions.java | 2 +- .../util/crafting/ItemMatcher.java | 4 +- .../util/crafting/ItemRecord.java | 2 +- .../util/crafting/RecipeDeconstructor.java | 6 +- .../util/farming/VirtualCrop.java | 14 +- src/main/resources/META-INF/mods.toml | 4 +- src/main/resources/pack.mcmeta | 2 +- .../blocks/NativeBlockContractTest.java | 36 +++-- .../blocks/OreHarvestContractTest.java | 64 ++++++++ .../entities/HydroturbinePersistenceTest.java | 18 +-- .../graphics/RendererBufferContractTest.java | 40 ++--- .../electricadvantage/init/VillagesTest.java | 4 +- .../ElectricDrillPersistenceTest.java | 18 ++- .../machines/LaserTurretGeometryTest.java | 12 +- .../ElectricLegacyMigrationsTest.java | 2 +- .../resources/BlockLootResourceTest.java | 4 +- .../resources/BuildWorkflowContractTest.java | 14 +- .../RecipeRegistrationThreadTest.java | 4 +- tools/verification/AuditedJUnit.java | 55 +++++++ tools/verification/Verify-ElectricEcj.ps1 | 146 ++++++++++++++++++ tools/verify-native-port.js | 115 ++++++++++++++ 85 files changed, 1259 insertions(+), 692 deletions(-) create mode 100644 docs/NATIVE116.md create mode 100644 src/test/java/zone/moddev/mc/electricadvantage/blocks/OreHarvestContractTest.java create mode 100644 tools/verification/AuditedJUnit.java create mode 100644 tools/verification/Verify-ElectricEcj.ps1 create mode 100644 tools/verify-native-port.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c86c599..aa94c41 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,16 +1,16 @@ -name: Electric Advantage 1.15 CI +name: Electric Advantage 1.16 CI on: push: - branches: [master-1.15.2, 'feature/**'] + branches: [master-1.16.5, 'feature/**'] pull_request: - branches: [master-1.15.2] + branches: [master-1.16.5] permissions: contents: read concurrency: - group: electricadvantage-1.15-${{ github.workflow }}-${{ github.ref }} + group: electricadvantage-1.16-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: @@ -24,23 +24,36 @@ jobs: - name: Use canonical LF dependency inputs # Apply before every dependency checkout, including OreSpawn. run: git config --global core.autocrlf false + - name: Require final PowerAdvantage pin + id: pins + shell: bash + run: | + set -euo pipefail + power_ref="$(sed -n 's/^poweradvantage_source_ref=//p' gradle.properties | tr -d '\r')" + power_sha="$(sed -n 's/^poweradvantage_deobf_sha256=//p' gradle.properties | tr -d '\r')" + if [[ "$power_ref" != "098d4625abc8a849bd1a11dcf697b3fee0cade7b" || "$power_sha" != "78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3" ]]; then + echo "PowerAdvantage 1.16.5 source/deobf pin differs from the audited candidate" >&2 + exit 1 + fi + echo "power_ref=$power_ref" >> "$GITHUB_OUTPUT" - name: Check out pinned OreSpawn uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/OreSpawn - ref: 5613baf876747ed071cb7ad7e2aff4e0ce4f0a03 + ref: a113e5d767169189f0e35ade1e173a12d550b00e path: .ci-dependencies/OreSpawn - name: Check out pinned Base Metals uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/BaseMetals - ref: ac1781e7cade15045ffe0135077087b4d1722603 + ref: 995f6cc4dd2d5eecc628a42e5c43fa5390c24bca path: .ci-dependencies/BaseMetals - - name: Check out PowerAdvantage 1.15.2 + - name: Check out PowerAdvantage 1.16.5 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/PowerAdvantage - ref: 6666099a734eba16561d98c86f3f4bb1b7c742f7 + # Local-only Power source; publish upstream before hosted builds. + ref: 098d4625abc8a849bd1a11dcf697b3fee0cade7b path: .ci-dependencies/PowerAdvantage - name: Install pinned Java 25 Mavenizer runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 @@ -66,7 +79,7 @@ jobs: -Porg.gradle.java.installations.auto-download=false" >> "$GITHUB_ENV" - name: Set up Gradle uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6 - - name: Build 1.15.2 dependency chain + - name: Build 1.16.5 dependency chain id: dependencies shell: bash run: | @@ -77,12 +90,12 @@ jobs: chmod +x "$orespawn/gradlew" "$basemetals/gradlew" "$power/gradlew" (cd "$orespawn" && ./gradlew $MMD_GRADLE_TOOLCHAINS jar --no-daemon --stacktrace) (cd "$basemetals" && ./gradlew $MMD_GRADLE_TOOLCHAINS jar --no-daemon --stacktrace) - osjar="$orespawn/build/libs-dev/OreSpawn-4.1.1.115021-deobf.jar" - bmjar="$basemetals/build/libs-dev/BaseMetals-3.0.2.115021-deobf.jar" + osjar="$orespawn/build/libs-dev/OreSpawn-4.1.0.116051-deobf.jar" + bmjar="$basemetals/build/libs-dev/BaseMetals-3.1.1.116051-deobf.jar" (cd "$power" && ./gradlew $MMD_GRADLE_TOOLCHAINS jar verifyReleaseDependencies \ -PbaseMetalsDeobfJar="$bmjar" -PoreSpawnDeobfJar="$osjar" \ --no-daemon --stacktrace) - powerjar="$power/build/libs-dev/PowerAdvantage-2.4.6.115021-deobf.jar" + powerjar="$power/build/libs-dev/PowerAdvantage-2.4.7.116051-deobf.jar" test -f "$osjar" && test -f "$bmjar" && test -f "$powerjar" echo "orespawn=$osjar" >> "$GITHUB_OUTPUT" echo "basemetals=$bmjar" >> "$GITHUB_OUTPUT" @@ -100,20 +113,20 @@ jobs: - name: Upload audited release candidate uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: ElectricAdvantage-1.15.2-${{ github.sha }} + name: ElectricAdvantage-1.16.5-${{ github.sha }} if-no-files-found: error retention-days: 30 path: | - build/libs/ElectricAdvantage-2.2.7.115021.jar - build/libs/ElectricAdvantage-2.2.7.115021-sources.jar - build/libs/ElectricAdvantage-2.2.7.115021-javadoc.jar + build/libs/ElectricAdvantage-2.2.8.116051.jar + build/libs/ElectricAdvantage-2.2.8.116051-sources.jar + build/libs/ElectricAdvantage-2.2.8.116051-javadoc.jar build/release/SHA256SUMS CHANGELOG.txt - name: Upload diagnostics on failure if: failure() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: ElectricAdvantage-1.15.2-diagnostics-${{ github.sha }} + name: ElectricAdvantage-1.16.5-diagnostics-${{ github.sha }} if-no-files-found: ignore retention-days: 14 path: | diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 69df538..b011263 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,9 +2,9 @@ name: CodeQL on: push: - branches: [master-1.15.2, 'feature/**'] + branches: [master-1.16.5, 'feature/**'] pull_request: - branches: [master-1.15.2] + branches: [master-1.16.5] schedule: - cron: '59 7 * * 4' @@ -24,23 +24,36 @@ jobs: - name: Use canonical LF dependency inputs # Apply before every dependency checkout, including OreSpawn. run: git config --global core.autocrlf false + - name: Require final PowerAdvantage pin + id: pins + shell: bash + run: | + set -euo pipefail + power_ref="$(sed -n 's/^poweradvantage_source_ref=//p' gradle.properties | tr -d '\r')" + power_sha="$(sed -n 's/^poweradvantage_deobf_sha256=//p' gradle.properties | tr -d '\r')" + if [[ "$power_ref" != "098d4625abc8a849bd1a11dcf697b3fee0cade7b" || "$power_sha" != "78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3" ]]; then + echo "PowerAdvantage 1.16.5 source/deobf pin differs from the audited candidate" >&2 + exit 1 + fi + echo "power_ref=$power_ref" >> "$GITHUB_OUTPUT" - name: Check out pinned OreSpawn uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/OreSpawn - ref: 5613baf876747ed071cb7ad7e2aff4e0ce4f0a03 + ref: a113e5d767169189f0e35ade1e173a12d550b00e path: .ci-dependencies/OreSpawn - name: Check out pinned Base Metals uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/BaseMetals - ref: ac1781e7cade15045ffe0135077087b4d1722603 + ref: 995f6cc4dd2d5eecc628a42e5c43fa5390c24bca path: .ci-dependencies/BaseMetals - - name: Check out PowerAdvantage 1.15.2 + - name: Check out PowerAdvantage 1.16.5 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/PowerAdvantage - ref: 6666099a734eba16561d98c86f3f4bb1b7c742f7 + # Local-only Power source; publish upstream before hosted builds. + ref: 098d4625abc8a849bd1a11dcf697b3fee0cade7b path: .ci-dependencies/PowerAdvantage - name: Install pinned Java 25 Mavenizer runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 @@ -66,7 +79,7 @@ jobs: -Porg.gradle.java.installations.auto-download=false" >> "$GITHUB_ENV" - name: Set up Gradle uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6 - - name: Build 1.15.2 dependency chain + - name: Build 1.16.5 dependency chain id: dependencies shell: bash run: | @@ -77,12 +90,12 @@ jobs: chmod +x "$orespawn/gradlew" "$basemetals/gradlew" "$power/gradlew" (cd "$orespawn" && ./gradlew $MMD_GRADLE_TOOLCHAINS jar --no-daemon --stacktrace) (cd "$basemetals" && ./gradlew $MMD_GRADLE_TOOLCHAINS jar --no-daemon --stacktrace) - osjar="$orespawn/build/libs-dev/OreSpawn-4.1.1.115021-deobf.jar" - bmjar="$basemetals/build/libs-dev/BaseMetals-3.0.2.115021-deobf.jar" + osjar="$orespawn/build/libs-dev/OreSpawn-4.1.0.116051-deobf.jar" + bmjar="$basemetals/build/libs-dev/BaseMetals-3.1.1.116051-deobf.jar" (cd "$power" && ./gradlew $MMD_GRADLE_TOOLCHAINS jar verifyReleaseDependencies \ -PbaseMetalsDeobfJar="$bmjar" -PoreSpawnDeobfJar="$osjar" \ --no-daemon --stacktrace) - powerjar="$power/build/libs-dev/PowerAdvantage-2.4.6.115021-deobf.jar" + powerjar="$power/build/libs-dev/PowerAdvantage-2.4.7.116051-deobf.jar" test -f "$osjar" && test -f "$bmjar" && test -f "$powerjar" echo "orespawn=$osjar" >> "$GITHUB_OUTPUT" echo "basemetals=$bmjar" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/validate-gradle-build.yml b/.github/workflows/validate-gradle-build.yml index 7d47484..fc66575 100644 --- a/.github/workflows/validate-gradle-build.yml +++ b/.github/workflows/validate-gradle-build.yml @@ -3,11 +3,11 @@ name: Validate Gradle Wrapper on: push: branches: - - master-1.15.2 + - master-1.16.5 - 'feature/**' pull_request: branches: - - master-1.15.2 + - master-1.16.5 permissions: contents: read diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 25e3660..2c2a903 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,14 @@ +Electric Advantage 2.2.8.116051 (local port candidate) + +- Target Minecraft 1.16.5, Forge 36.2.34, official 1.16.5 mappings and MCP 20210115.111550. +- Retain Java 8 runtime/bytecode, Java 17 Gradle, Java 25 Mavenizer, ForgeGradle 7.0.34 and Gradle 9.6.1. +- Use native renderer buffers, state-aware tile persistence and world-only Power Advantage conduit callbacks. +- Retain lithium/sulfur mining levels through native correct-tool checks and serialize recipe-condition registration with enqueueWork. +- Preserve registry IDs, legacy aliases, NBT keys, balance constants, recipes, discoveries and asset bytes from the accepted 1.15 source. +- Pin the exact local Power Advantage 2.4.7.116051 bootstrap-B source/development artifact; retain fail-closed release audits and no dependency embedding. +- Pass local production/test compilation, all 47 Java tests, release audits and Eclipse production-classpath checks. +- Keep packaged runtime qualification, world-upgrade checks and manual acceptance pending. + Electric Advantage 2.2.7.115021 - Target Minecraft 1.15.2, Forge 31.2.57 and snapshot 20200514-1.15.1/MCP 20200515.085601. diff --git a/README.md b/README.md index 37fbe72..08d2554 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,101 @@ -# ElectricAdvantage +# Electric Advantage -**Minecraft 1.15.2, version 2.2.7.115021.** See the -[shared test record](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.15.2/docs/1.15/CURRENT-QUALIFICATION.md) -for exact jars, automated machine and upgrade results, and remaining manual -checks. Visuals and recipe unlocks were accepted on 27 October 2026. Historical -[1.14 test results](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.14.4/docs/1.14/BROADER-QUALIFICATION.md) -are not 1.15 qualification evidence. +**Minecraft 1.16.5 port candidate, version 2.2.8.116051.** Compilation, all 47 Java +tests, release audits and Eclipse checks passed locally against Power bootstrap B. +Bootstrap-A evidence is preserved separately. Packaged runtime +qualification and manual acceptance are pending; this is not a published +release. See [the native port checklist](docs/NATIVE116.md). +The [accepted 1.15 record](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.15.2/docs/1.15/CURRENT-QUALIFICATION.md) +is a behavior reference, not evidence that this target passes. -Electric Advantage adds electric machines, generation, storage, automation, and defence to Power Advantage for Minecraft 1.15.2. +Electric Advantage adds electric machines, generation, storage, automation, +and defence to Power Advantage for Minecraft 1.16.5. -Every crafting and vanilla smelting variant has an ingredient-triggered recipe-book discovery. See the [shared material checklist and discovery tests](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.13.2/docs/1.13/RECIPE-DISCOVERY.md) and [manufacturing progression audit](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.13.2/docs/1.13/MANUFACTURING-PROGRESSION.md). Regenerate unlock JSON after recipe changes with `node tools/generate-recipe-unlocks.js`; `check` audits recipe coverage and criteria. Custom machine and crushing recipes are not crafting-book entries. +## Build Target -## Building Minecraft 1.15.2 +The build targets Forge `36.2.34`, official `1.16.5` mappings and MCP +`20210115.111550`, using ForgeGradle `7.0.34`, Renamer `1.1.5` and Gradle +`9.6.1`. Run Gradle with Temurin `17.0.1+12`; production code and Minecraft +use Temurin `8.0.502+7`. Mavenizer needs Temurin `25.0.3+9.0.LTS`, including +on a cold cache. CI registers all three JDK paths and disables toolchain +inference and downloads. -The `master-1.15.2` build targets Forge `31.2.57`, mappings `snapshot 20200514-1.15.1`, -and MCP `20200515.085601`, using ForgeGradle `7.0.34`, Renamer `1.1.5` and Gradle `9.6.1`. -Run Gradle with Temurin `17.0.1+12`; production code uses Temurin `8.0.502+7`. -Mavenizer also needs Temurin `25.0.3+9.0.LTS`, including on a cold cache. CI explicitly -registers all three JDK paths and disables toolchain auto-detection and downloads. +Build inputs are separate, non-embedded deobfuscated jars: -Build the matching 1.15 PowerAdvantage, Base Metals and OreSpawn deobf jars first. -Dependency versions, checksums and the exact Power source reference belong in -`gradle.properties`. Release audits reject missing or placeholder pins; do not -bypass those checks or substitute another target's dependencies. Power Advantage -`2.4.6.115021` is pinned to source `6666099a734eba16561d98c86f3f4bb1b7c742f7`. -Base Metals `3.0.2.115021` and OreSpawn `4.1.1.115021` also have exact source and SHA-256 pins. -Base Metals source `ac1781e7cade15045ffe0135077087b4d1722603` and the Power -source pin above identify the exact tested dependencies. CI builds them before -Electric Advantage; none is embedded in the Electric Advantage jar. +- Power Advantage `2.4.7.116051`: source `098d4625abc8a849bd1a11dcf697b3fee0cade7b`. +- Base Metals `3.1.1.116051`: source `995f6cc4dd2d5eecc628a42e5c43fa5390c24bca`. +- OreSpawn `4.1.0.116051`: source `a113e5d767169189f0e35ade1e173a12d550b00e`. -With the standard sibling layout: +Exact checksums are recorded in `gradle.properties`. Power deobf SHA-256 is +`78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3`. +Its source is local-only; hosted reproducibility is pending upstream source +publication. Do not bypass the release audits or substitute a preliminary jar. +Use immutable copies for verification, not a sibling's output that another +build may replace. CI rejects pins that differ from this audited candidate. -```text -cd ..\..\PowerAdvantage -gradlew.bat deobfJar -``` - -For local development with the matching native jars, compile and run tests: +With an authorized build slot, pass the immutable input paths and run: ```text -gradlew.bat classes test deobfJar +gradlew.bat classes test deobfJar -PpowerAdvantageDeobfJar= -PbaseMetalsDeobfJar= -PoreSpawnDeobfJar= ``` -With the exact Power dependency pinned, run the complete release gates: +The complete deterministic release gates are: ```text gradlew.bat clean check build javadoc verifyReleaseDependencies verifyReleaseArtifacts writeReleaseChecksums verifyEclipseProductionClasspath ``` -Alternative layouts may pass `-PpowerAdvantageDeobfJar=`, `-PbaseMetalsDeobfJar=`, and `-PoreSpawnDeobfJar=`. None of those dependencies is embedded. +These gates passed locally on 27 October 2026 against the pinned immutable +dependencies. They do not replace packaged client/server tests, +disposable-world migration checks or manual acceptance. +Do not run another build concurrently against a shared Gradle cache. -For Eclipse, import this repository as an existing Gradle project and run: +Static checks need no Gradle or game launch: ```text -gradlew.bat cleanEclipse verifyEclipseProductionClasspath +node tools/verify-native-port.js --report build/native-port-static.json +node tools/generate-recipe-unlocks.js --check ``` -Refresh the project in Eclipse, allow its Java build to finish, and launch the generated `runClient.launch`. Eclipse launches discover ElectricAdvantage from `bin/main`; command-line Gradle launches use `build/forge-run-mod-classes/main`. The Eclipse audit checks that discovery points at the same production output Eclipse compiles into. +The static contract compares resources, identity strings and numeric constants +with accepted source `74aa1cee1ddec821ebcd12b9f8b0515b7aec61d9`. Its reports are +not compilation, gameplay or migration results. -The Eclipse resource root is `build/resources/main`, so its builder copies expanded mod metadata rather than raw source templates. Refresh the Gradle project and clean/rebuild after this setup changes. After resource/version edits, run `processResources` or refresh Gradle before launching; do not put `src/main/resources` back on the Eclipse Java build path. +## Eclipse -## Compatibility - -For an all-Advantage play-test, run `prepareCombinedEclipseLaunch` in the sibling PowerAdvantage checkout and select its `runClientAllAdvantage.launch`. Combined 1.15 client resources and gameplay require new target-specific evidence; resource checks do not replace gameplay testing. +Import this repository as an existing Gradle project. Once dependencies and +build access are available, run `cleanEclipse verifyEclipseProductionClasspath`. +Eclipse mod discovery uses `bin/main`; command-line launches use +`build/forge-run-mod-classes/main`. The production classpath audit checks those +paths and excludes test output. -Automated coverage is bounded to the recorded scenarios. It does not establish every -in-world GUI, rendering, sound, control or weapon interaction, multiplayer behavior, -or compatibility with arbitrary third-party mods. Unit/resource tests alone are not -runtime or world-upgrade evidence. +The Eclipse resource root is `build/resources/main`, so its builder copies +expanded metadata. After resource or version edits, process resources before +launching. Do not add raw source metadata to the production classpath. -The implementation namespace is `zone.moddev.mc.electricadvantage`. Runtime identities, registries, tile/entity IDs, NBT, recipes, tags, OreSpawn provider IDs, and assets remain stable. Electric registers its legacy state, tile, and hydroturbine aliases with PowerAdvantage's shared migration hook. +## Compatibility -The RF- and Tech Reborn-labelled converters belong to Power Advantage and now use Forge Energy. -The historical [1.13 migration guide](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.13.2/docs/1.13/MIGRATION.md) explains the legacy conversion and backup process; the shared 1.15 test record lists the completed upgrade routes and their limits. Always make a whole-world backup before upgrading, keep the complete set of migration backups, and test a disposable copy first. Check that every other mod supports the target version; bounded Advantage tests do not qualify unrelated mods or an entire modpack. +The implementation namespace remains `zone.moddev.mc.electricadvantage`. +Runtime registries, legacy aliases, tile/entity IDs, NBT keys, recipe IDs, +ratios, tags, OreSpawn provider IDs and assets are retained. Electric uses +Power Advantage's shared migration hook, dimension-key network registry, +capability adapters and native lifecycle contracts. It does not create +synthetic numeric dimension IDs or a second capability implementation. + +All 46 crafting variants and four smelting recipes retain ingredient-triggered +recipe-book discoveries. The eight Base Metals crushing recipes are not +crafting-book entries. Regenerate unlocks only after an intentional recipe +change; `check` audits their coverage and criteria. + +Base Metals remains optional in Forge metadata; CurseForge's existing required +installation relationship is unchanged. Typed integration uses the matching +Base Metals and OreSpawn APIs without embedding either mod. + +The RF- and Tech Reborn-labelled converters belong to Power Advantage and use +Forge Energy. Visuals, GUI interaction, sound, weapons, hydroturbine behavior, +multiplayer, tag reloads, dimensions and world upgrades need target-specific +verification. No 1.16 publication is authorized before manual acceptance. + +Always back up a whole world before upgrading and test only disposable copies. +Keep migration backups and failed evidence. Bounded Advantage results never +qualify unrelated mods or an arbitrary existing modpack. diff --git a/build.gradle b/build.gradle index a0e8bd2..257db3f 100644 --- a/build.gradle +++ b/build.gradle @@ -94,7 +94,7 @@ minecraft { def forgeRunModClassesDirectory = layout.buildDirectory.dir('forge-run-mod-classes/main') def forgeMainOutputPath = forgeRunModClassesDirectory.get().asFile.absolutePath def mainModClasses = "${mod_id}%%${forgeMainOutputPath}${File.pathSeparator}${mod_id}%%${forgeMainOutputPath}" - def forge31RunTargets = [client: 'fmluserdevclient', server: 'fmluserdevserver', data: 'fmluserdevdata'] + def forge36RunTargets = [client: 'fmluserdevclient', server: 'fmluserdevserver', data: 'fmluserdevdata'] runs { configureEach { mainClass = 'net.minecraftforge.userdev.LaunchTesting' @@ -102,7 +102,7 @@ minecraft { systemProperty 'forge.logging.markers', 'REGISTRIES' systemProperty 'forge.logging.console.level', 'info' mods { electricadvantage { source sourceSets.main } } - environment 'target', forge31RunTargets[name] + environment 'target', forge36RunTargets[name] environment 'MCP_MAPPINGS', "${mapping_channel}_${mapping_version}" environment 'MCP_VERSION', mcp_version environment 'FORGE_VERSION', forge_version @@ -130,7 +130,7 @@ sourceSets.main.resources { def forgeRunModClassesDirectory = layout.buildDirectory.dir('forge-run-mod-classes/main') def prepareForgeRunModClasses = tasks.register('prepareForgeRunModClasses', Sync) { group = 'ide' - description = 'Merges classes and processed resources for Forge 1.15 launches.' + description = 'Merges classes and processed resources for Forge 1.16 launches.' dependsOn tasks.named('classes') from sourceSets.main.output into forgeRunModClassesDirectory @@ -178,18 +178,18 @@ if (!powerAdvantageDeobfJar.isFile()) { // These defaults follow the sibling MMD checkout layout. They are constants // here so another developer can override them without editing the script. def baseMetalsDeobfJar = file(providers.gradleProperty('baseMetalsDeobfJar') - .getOrElse('../../../../BaseMetals/BaseMetals 115/BaseMetals/build/libs-dev/' - + 'BaseMetals-3.0.2.115021-deobf.jar')) + .getOrElse('../../../../BaseMetals/BaseMetals 116/BaseMetals/build/libs-dev/' + + 'BaseMetals-3.1.1.116051-deobf.jar')) if (!baseMetalsDeobfJar.isFile()) { throw new GradleException("Missing Base Metals deobf jar at ${baseMetalsDeobfJar}. " - + "Build Base Metals 1.15 first, or pass -PbaseMetalsDeobfJar=.") + + "Build Base Metals 1.16 first, or pass -PbaseMetalsDeobfJar=.") } def oreSpawnDeobfJar = file(providers.gradleProperty('oreSpawnDeobfJar') - .getOrElse('../../../../MinecraftMineralogy/OS115/OreSpawn/build/libs-dev/' - + 'OreSpawn-4.1.1.115021-deobf.jar')) + .getOrElse('../../../../MinecraftMineralogy/OS116/OreSpawn/build/libs-dev/' + + 'OreSpawn-4.1.0.116051-deobf.jar')) if (!oreSpawnDeobfJar.isFile()) { throw new GradleException("Missing OreSpawn deobf jar at ${oreSpawnDeobfJar}. " - + "Build OreSpawn 1.15 first, or pass -PoreSpawnDeobfJar=.") + + "Build OreSpawn 1.16 first, or pass -PoreSpawnDeobfJar=.") } dependencies { @@ -341,17 +341,17 @@ tasks.register('verifyReleaseConfiguration') { group = 'verification' description = 'Validates release identity, target metadata, and dependency policy.' doLast { - if (new JsonSlurper().parse(file('src/main/resources/pack.mcmeta')).pack.pack_format != 5) { - throw new GradleException('Minecraft 1.15.2 resources must use pack format 5') + if (new JsonSlurper().parse(file('src/main/resources/pack.mcmeta')).pack.pack_format != 6) { + throw new GradleException('Minecraft 1.16.5 resources must use pack format 6') } - if (project.mod_version != '2.2.7.115021') { + if (project.mod_version != '2.2.8.116051') { throw new GradleException("Unexpected ElectricAdvantage release version: ${project.mod_version}") } - if (project.minecraft_version != '1.15.2' - || project.forge_version != '31.2.57' - || project.mapping_channel != 'snapshot' - || project.mapping_version != '20200514-1.15.1' - || project.mcp_version != '20200515.085601') { + if (project.minecraft_version != '1.16.5' + || project.forge_version != '36.2.34' + || project.mapping_channel != 'official' + || project.mapping_version != '1.16.5' + || project.mcp_version != '20210115.111550') { throw new GradleException('Unexpected Minecraft, Forge, or mappings target') } if (project.loader_name != 'forge' || project.loader_code != '1' @@ -369,33 +369,36 @@ tasks.register('verifyReleaseConfiguration') { } if (project.cf_requirements != 'power-advantage,base-metals' || project.cf_optionals != '' - || project.cf_versions != '1.15.2') { + || project.cf_versions != '1.16.5') { throw new GradleException('Unexpected CurseForge dependency or game-version metadata') } - if (project.poweradvantage_version != '2.4.6.115021' + if (!project.poweradvantage_source_ref || !project.poweradvantage_deobf_sha256) { + throw new GradleException('PowerAdvantage 1.16.5 final source and deobf SHA-256 pins are pending') + } + if (project.poweradvantage_version != '2.4.7.116051' || project.poweradvantage_source_repository != 'MinecraftModDevelopmentMods/PowerAdvantage' - || project.poweradvantage_source_ref != '6666099a734eba16561d98c86f3f4bb1b7c742f7' - || project.poweradvantage_deobf_sha256 != 'F5029356CB837E7D782BA59D4C3B961CE0AAA116B739F14DA63F0A13562A2D1F') { + || project.poweradvantage_source_ref != '098d4625abc8a849bd1a11dcf697b3fee0cade7b' + || project.poweradvantage_deobf_sha256 != '78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3') { throw new GradleException('Unexpected PowerAdvantage compile dependency identity') } - if (project.basemetals_version != '3.0.2.115021' - || project.orespawn_version != '4.1.1.115021' - || project.basemetals_source_commit != 'ac1781e7cade15045ffe0135077087b4d1722603' - || project.orespawn_source_commit != '5613baf876747ed071cb7ad7e2aff4e0ce4f0a03' - || project.basemetals_deobf_sha256 != '426FE639C97E1DE4F6624957E3CBDE68A5FB7D415A1047903A29DCB35FD9ADA2' - || project.orespawn_deobf_sha256 != '358B13375A4B60622C491D6729290971A446FF14D524A600CA13710934DB3FDC' - || project.forge_installer_sha256 != '84FD49A743978421B26F62AC78222289FE892A46F996CF11CB5E05B7441A7773') { + if (project.basemetals_version != '3.1.1.116051' + || project.orespawn_version != '4.1.0.116051' + || project.basemetals_source_commit != '995f6cc4dd2d5eecc628a42e5c43fa5390c24bca' + || project.orespawn_source_commit != 'a113e5d767169189f0e35ade1e173a12d550b00e' + || project.basemetals_deobf_sha256 != 'A7B0C4F394DFAF4E11E0275B1A86CB1D47C7AF8E175759D9BB84F965C684466D' + || project.orespawn_deobf_sha256 != 'DCEE75480C9DD70EE58B218AAE799C5FAB0525DAF9A05455270F1570C24F7F8F' + || project.forge_installer_sha256 != '53B73DBBCC486F38726E76CE923B13381044984C83C762847C7193340F97130F') { throw new GradleException('Unexpected native dependency pins') } String mainSource = file( 'src/main/java/zone/moddev/mc/electricadvantage/ElectricAdvantage.java').getText('UTF-8') if (!mainSource.contains('MODID = "electricadvantage"') - || !mainSource.contains('VERSION = "2.2.7.115021"')) { + || !mainSource.contains('VERSION = "2.2.8.116051"')) { throw new GradleException('ElectricAdvantage source identity changed') } String metadata = file('src/main/resources/META-INF/mods.toml').getText('UTF-8').replace('\r\n', '\n') ['modId="electricadvantage"', 'modId="poweradvantage"', 'modId="basemetals"', - 'versionRange="[2.4.6.115021,3.0.0)"'].each { marker -> + 'versionRange="[2.4.7.116051,3.0.0)"'].each { marker -> if (!metadata.contains(marker)) { throw new GradleException("Source mods.toml is missing ${marker}") } @@ -429,7 +432,7 @@ tasks.register('verifyReleaseDependencies') { } def manifest = new Manifest(zip.getInputStream(zip.getEntry('META-INF/MANIFEST.MF'))).mainAttributes if (manifest.getValue('Implementation-Version') != project.poweradvantage_version - || manifest.getValue('Built-On') != '1.15.2-31.2.57') { + || manifest.getValue('Built-On') != '1.16.5-36.2.34') { throw new GradleException('PowerAdvantage dependency manifest has the wrong version') } } diff --git a/docs/NATIVE116.md b/docs/NATIVE116.md new file mode 100644 index 0000000..b34b191 --- /dev/null +++ b/docs/NATIVE116.md @@ -0,0 +1,114 @@ +# Native 1.16.5 Port Checks + +This checklist separates source changes, deterministic tests, packaged runtime +checks and manual acceptance. Only checks actually executed may be marked passed. + +## Inputs + +- Electric source baseline: `74aa1cee1ddec821ebcd12b9f8b0515b7aec61d9`. +- Electric candidate: `2.2.8.116051`; Power candidate: `2.4.7.116051`. +- Forge `36.2.34`, official `1.16.5`, MCP `20210115.111550`. +- Base Metals `3.1.1.116051`, source `995f6cc4dd2d5eecc628a42e5c43fa5390c24bca`. +- Base deobf SHA-256: `A7B0C4F394DFAF4E11E0275B1A86CB1D47C7AF8E175759D9BB84F965C684466D`. +- OreSpawn `4.1.0.116051`, source `a113e5d767169189f0e35ade1e173a12d550b00e`. +- OreSpawn deobf SHA-256: `DCEE75480C9DD70EE58B218AAE799C5FAB0525DAF9A05455270F1570C24F7F8F`. +- Power bootstrap B source: `098d4625abc8a849bd1a11dcf697b3fee0cade7b` (local-only). +- Power bootstrap B deobf SHA-256: `78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3`. +- Verified immutable Power release SHA-256: `60E10F94F447D948244EF088A3B77134C13FBEBCCA1D8DB6210E8630F94A051F`. + +Copy the final verified jars to immutable local input paths before building. +Do not compile against a sibling output that another worker may overwrite. +The release audit retains exact source/hash expectations for this candidate. +Do not relax those checks. Publish the local-only Power source upstream before +hosted build or release readiness is claimed. + +## Source Contracts + +- All recipe, advancement, tag, loot, model, texture and translation resources + are retained byte-for-byte except native pack metadata and dependency ranges. +- All production string identities and numeric constants match the accepted + baseline, apart from the candidate version string. +- The drill uses world-only conduit callbacks. Power owns `RegistryKey` + lookup and capability/NBT lifecycle; Electric adds no competing adapters. +- Tile persistence uses `load(BlockState, CompoundNBT)` and `save(CompoundNBT)`. + Turret update tags receive the native state and retain render synchronization. +- Lithium needs a level-1 pickaxe; sulfur needs level 0. The native correct-tool + prerequisite must be enabled, not merely the harvest-tool metadata. +- Scaffold occlusion, redstone conduction and full collision are separate checks. + Solar redstone conduction remains explicitly true. A renamed property flag is + not evidence of equivalent suffocation, pathfinding, light or rendering behavior. +- Rendering retains all geometry, UVs, winding normals, light/overlay values, + timing, six drill directions, tracking settings and original test tolerances. +- Condition registration uses common setup's `enqueueWork`. Native tag loading + and reload integration belong to Power and still need runtime proof. +- Electric's tag resources contain no legacy `optional` arrays. Any future + optional reference must use `values: [{"id": "...", "required": false}]`. + +## Evidence Stages + +The initial static report is preserved at `evidence/native-port-static-red.json`; +it retains the expected failures against the unported 1.15 source. Later reports +use new names and must not overwrite failed or partial evidence. + +Run the static checker and recipe-unlock check before compilation. These do not +load Minecraft or establish Java compilation. The Java suite retains the 115 +tests and adds actual Forge harvest-hook eligibility checks. + +### Bootstrap A Results (27 October 2026) + +These results use Power bootstrap A, source `ce90c24c302d0ff3565db2db0c6c94a3b5f21f83` +and deobf SHA-256 `8BBB03DD7E4AF08A7390A161ED5AA94E292BEE56EF60E550B5512E967E0E9174`. +These results and immutable jars remain preserved. Bootstrap B adds only the +parent's constructor-time GUI matrix initialization; it does not change the API. + +- Production/test compilation passed with the exact pinned dependencies. +- All 47 Java tests passed, with zero failures, errors or skips. Both earlier + failed test reports remain in `evidence/native116-test-red-01` and `-02`. +- The native persistence tests now pass an explicit drill state to `load` before + world attachment and bootstrap native registries before constructing blocks. + Their progress, energy, geometry and NBT expectations are unchanged. +- `clean cleanEclipse check build javadoc verifyReleaseDependencies + verifyReleaseArtifacts writeReleaseChecksums verifyEclipseProductionClasspath` + passed. The clean suite reused the successful Java test result from Gradle's + cache; the preceding successful test run executed the suite directly. +- The full-suite log is `evidence/native116-full-suite-01.log`. The failed + launcher/compile logs and static red reports remain alongside it. +- Java 8 bytecode, exact dependency hashes, no dependency embedding, model/tag + resource checks, release packaging and production Eclipse paths passed their + deterministic audits. Javadoc retains one pre-existing empty-return warning; + Gradle reports existing deprecations for its future version 10. + +### Bootstrap B Revalidation + +The exact B source/deobf pins above are configured. The clean full suite passed +against the immutable B jar on 27 October 2026 with `--rerun-tasks` and +`--no-build-cache`: production/test compilation, all 47 Java tests (zero failures, +errors or skips), release configuration/dependency/artifact/checksum audits and +production Eclipse generation/classpath checks. No tests were reused from cache. + +The log is `evidence/native116-bootstrap-b-full-suite-01.log`; raw Java reports are +preserved in `evidence/native116-bootstrap-b-test-green-01`. The ten static source +contracts and all 50 recipe unlocks also pass. The shared-cache lease was released +after the Gradle process completed. No Minecraft client or server was launched. + +Frozen B artifacts are under `evidence/native116-bootstrap-b-candidate`. The A +reports, handoff and candidate directory remain unchanged. The B handoff is +`evidence/native116-bootstrap-b-handoff.json`. + +Remaining runtime and acceptance work, only under an explicit runtime lease: + +1. Test the packaged candidate's recipes, + unlocks, native tags, condition modes, resource reload and restart behavior. +2. Compare machine inventory, energy, fluids, processing ratios, redstone and + comparator behavior against the accepted 115 behavior. +3. Test fresh and disposable upgraded worlds, all legacy aliases, repeated + load/save without ticking, drill relocation, pending growth work, turbine + parent links, turret ownership/target state, dimensions and chunk lifecycle. +4. Verify real player mining below/at the required level, sulfur drops and Silk + Touch, ordinary block/inventory drops, hidden pump pipes and network removal. +5. Manually inspect all GUIs, textures, beam directions/lighting, turret controls, + hydroturbine orientation/spin, sounds, interaction and multiplayer behavior. + +No Minecraft runtime, packaged smoke, world-upgrade pass +or manual acceptance is claimed. Commits, pushes, PRs, +tags and releases are outside the current authorization. diff --git a/gradle.properties b/gradle.properties index cb642bb..f663a51 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,15 +5,15 @@ org.gradle.caching=true org.gradle.parallel=false net.minecraftforge.gradle.merge-source-sets=false -minecraft_version=1.15.2 -minecraft_version_range=[1.15.2] -forge_version=31.2.57 -forge_installer_sha256=84FD49A743978421B26F62AC78222289FE892A46F996CF11CB5E05B7441A7773 -forge_version_range=[31.2.57,32) -loader_version_range=[31,) -mapping_channel=snapshot -mapping_version=20200514-1.15.1 -mcp_version=20200515.085601 +minecraft_version=1.16.5 +minecraft_version_range=[1.16.5] +forge_version=36.2.34 +forge_installer_sha256=53B73DBBCC486F38726E76CE923B13381044984C83C762847C7193340F97130F +forge_version_range=[36.2.34,37) +loader_version_range=[36,) +mapping_channel=official +mapping_version=1.16.5 +mcp_version=20210115.111550 loader_name=forge loader_code=1 @@ -26,25 +26,25 @@ curseforge_project_id=240985 mod_id=electricadvantage mod_name=Electric Advantage mod_license=GPL-3.0-only -mod_version=2.2.7.115021 +mod_version=2.2.8.116051 mod_group=zone.moddev.mc.electricadvantage mod_authors=DrCyano mod_description=Electric-powered machines and infrastructure for the Power Advantage platform. cf_requirements=power-advantage,base-metals cf_optionals= -cf_versions=1.15.2 +cf_versions=1.16.5 -poweradvantage_version=2.4.6.115021 +poweradvantage_version=2.4.7.116051 poweradvantage_source_repository=MinecraftModDevelopmentMods/PowerAdvantage -# Exact Power Advantage source and development jar used by local and CI builds. -poweradvantage_source_ref=6666099a734eba16561d98c86f3f4bb1b7c742f7 -poweradvantage_deobf_sha256=F5029356CB837E7D782BA59D4C3B961CE0AAA116B739F14DA63F0A13562A2D1F +# Exact local-only Power source and immutable development artifact; publish source before hosted builds. +poweradvantage_source_ref=098d4625abc8a849bd1a11dcf697b3fee0cade7b +poweradvantage_deobf_sha256=78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3 -basemetals_version=3.0.2.115021 -basemetals_source_commit=ac1781e7cade15045ffe0135077087b4d1722603 -basemetals_deobf_sha256=426FE639C97E1DE4F6624957E3CBDE68A5FB7D415A1047903A29DCB35FD9ADA2 +basemetals_version=3.1.1.116051 +basemetals_source_commit=995f6cc4dd2d5eecc628a42e5c43fa5390c24bca +basemetals_deobf_sha256=A7B0C4F394DFAF4E11E0275B1A86CB1D47C7AF8E175759D9BB84F965C684466D -orespawn_version=4.1.1.115021 -orespawn_source_commit=5613baf876747ed071cb7ad7e2aff4e0ce4f0a03 -orespawn_deobf_sha256=358B13375A4B60622C491D6729290971A446FF14D524A600CA13710934DB3FDC +orespawn_version=4.1.0.116051 +orespawn_source_commit=a113e5d767169189f0e35ade1e173a12d550b00e +orespawn_deobf_sha256=DCEE75480C9DD70EE58B218AAE799C5FAB0525DAF9A05455270F1570C24F7F8F diff --git a/src/main/java/zone/moddev/mc/electricadvantage/ElectricAdvantage.java b/src/main/java/zone/moddev/mc/electricadvantage/ElectricAdvantage.java index 63d24ef..7a1a0da 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/ElectricAdvantage.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/ElectricAdvantage.java @@ -33,12 +33,12 @@ import zone.moddev.mc.electricadvantage.recipe.RecipeConditions; import zone.moddev.mc.electricadvantage.migration.ElectricLegacyMigrations; -/** Forge 1.15 entry point for Electric Advantage. */ +/** Forge 1.16 entry point for Electric Advantage. */ @Mod(ElectricAdvantage.MODID) public final class ElectricAdvantage { public static final String MODID = "electricadvantage"; public static final String NAME = "Electric Advantage"; - public static final String VERSION = "2.2.7.115021"; + public static final String VERSION = "2.2.8.116051"; public static final Logger LOGGER = LogManager.getLogger(MODID); public static ElectricAdvantage INSTANCE; @@ -96,7 +96,7 @@ private static void migrateLegacyConfiguration() { private void commonSetup(FMLCommonSetupEvent event) { // CraftingHelper's shared condition map is not safe during parallel loading. - net.minecraftforge.fml.DeferredWorkQueue.runLater(RecipeConditions::register); + event.enqueueWork(RecipeConditions::register); ElectricAdvantageConfig.apply(); Recipes.init(); TreasureChests.init(FMLPaths.CONFIGDIR.get()); diff --git a/src/main/java/zone/moddev/mc/electricadvantage/blocks/ElectricScaffoldBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/blocks/ElectricScaffoldBlock.java index df6a451..1ff5442 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/blocks/ElectricScaffoldBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/blocks/ElectricScaffoldBlock.java @@ -13,10 +13,10 @@ /** Full-block electric track/scaffold with conduit behavior. */ public class ElectricScaffoldBlock extends BlockSimplePowerConduit { public ElectricScaffoldBlock() { - super(Properties.create(Material.PISTON).hardnessAndResistance(0.75F).notSolid(), + super(Properties.of(Material.PISTON).strength(0.75F).noOcclusion() + .isRedstoneConductor((state, world, pos) -> false), 2.0F / 16.0F, Power.ELECTRIC_POWER); } - @Override public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) { return VoxelShapes.fullCube(); } - @Override public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) { return VoxelShapes.fullCube(); } - @Override public boolean isNormalCube(BlockState state, IBlockReader world, BlockPos pos) { return false; } + @Override public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) { return VoxelShapes.block(); } + @Override public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) { return VoxelShapes.block(); } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/blocks/Ore.java b/src/main/java/zone/moddev/mc/electricadvantage/blocks/Ore.java index ad8b067..8047e7c 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/blocks/Ore.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/blocks/Ore.java @@ -11,8 +11,8 @@ import net.minecraft.item.ItemStack; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.enchantment.Enchantments; -import net.minecraft.world.storage.loot.LootContext; -import net.minecraft.world.storage.loot.LootParameters; +import net.minecraft.loot.LootContext; +import net.minecraft.loot.LootParameters; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -25,16 +25,16 @@ public class Ore extends Block { private final int harvestLevel; public Ore(ItemStack oreDrop, int pickLevel, int variation) { - super(Properties.create(Material.ROCK).sound(SoundType.STONE) - .hardnessAndResistance(1.5F + pickLevel, 5.0F * (1 + pickLevel))); + super(Properties.of(Material.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE) + .strength(1.5F + pickLevel, 5.0F * (1 + pickLevel))); dropItem = oreDrop.copy(); dropRange = variation + 1; harvestLevel = pickLevel; } public Ore(int pickLevel) { - super(Properties.create(Material.ROCK).sound(SoundType.STONE) - .hardnessAndResistance(1.5F + pickLevel, 5.0F * (1 + pickLevel))); + super(Properties.of(Material.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE) + .strength(1.5F + pickLevel, 5.0F * (1 + pickLevel))); dropItem = ItemStack.EMPTY; dropRange = 0; harvestLevel = pickLevel; @@ -45,12 +45,12 @@ public Ore(int pickLevel) { @Override public List getDrops(BlockState state, LootContext.Builder context) { - ItemStack tool = context.get(LootParameters.TOOL); + ItemStack tool = context.getOptionalParameter(LootParameters.TOOL); if (dropItem.isEmpty() || (tool != null - && EnchantmentHelper.getEnchantmentLevel(Enchantments.SILK_TOUCH, tool) > 0)) { + && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SILK_TOUCH, tool) > 0)) { return Collections.singletonList(new ItemStack(this)); } - Random random = context.getWorld().rand; + Random random = context.getLevel().random; ItemStack result = dropItem.copy(); result.setCount(dropItem.getCount() + (dropRange > 1 ? random.nextInt(dropRange) : 0)); return Collections.singletonList(result); diff --git a/src/main/java/zone/moddev/mc/electricadvantage/blocks/PumpPipeBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/blocks/PumpPipeBlock.java index 0da6a78..c4b10a1 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/blocks/PumpPipeBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/blocks/PumpPipeBlock.java @@ -9,37 +9,36 @@ import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShapes; import net.minecraft.util.math.shapes.ISelectionContext; -import net.minecraft.world.storage.loot.LootContext; +import net.minecraft.loot.LootContext; import net.minecraft.world.Explosion; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; /** Hidden pump intake column. */ public class PumpPipeBlock extends Block { - private static final VoxelShape SHAPE = VoxelShapes.create(0.25D, 0.0D, 0.25D, 0.75D, 1.0D, 0.75D); - public PumpPipeBlock() { super(Properties.create(Material.IRON).hardnessAndResistance(5.0F, 10.0F).variableOpacity().notSolid().noDrops()); } + private static final VoxelShape SHAPE = VoxelShapes.box(0.25D, 0.0D, 0.25D, 0.75D, 1.0D, 0.75D); + public PumpPipeBlock() { super(Properties.of(Material.METAL).strength(5.0F, 10.0F).dynamicShape().noOcclusion().isRedstoneConductor((state, world, pos) -> false).noDrops()); } @Override public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) { return SHAPE; } @Override public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) { return SHAPE; } - @Override public boolean isNormalCube(BlockState state, IBlockReader world, BlockPos pos) { return false; } @Override public java.util.List getDrops(BlockState state, LootContext.Builder context) { return java.util.Collections.emptyList(); } @Override - public void onReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moving) { + public void onRemove(BlockState state, World world, BlockPos pos, BlockState newState, boolean moving) { if (state.getBlock() != newState.getBlock()) destroyBelow(world, pos); - super.onReplaced(state, world, pos, newState, moving); + super.onRemove(state, world, pos, newState, moving); } - @Override public void onExplosionDestroy(World world, BlockPos pos, Explosion explosion) { + @Override public void wasExploded(World world, BlockPos pos, Explosion explosion) { destroyBelow(world, pos); - super.onExplosionDestroy(world, pos, explosion); + super.wasExploded(world, pos, explosion); } private void destroyBelow(World world, BlockPos pos) { - if (world.isRemote) return; - BlockPos cursor = pos.down(); + if (world.isClientSide) return; + BlockPos cursor = pos.below(); while (cursor.getY() > 0 && world.getBlockState(cursor).getBlock() == this) { - world.setBlockState(cursor, net.minecraft.block.Blocks.AIR.getDefaultState(), 3); - cursor = cursor.down(); + world.setBlock(cursor, net.minecraft.block.Blocks.AIR.defaultBlockState(), 3); + cursor = cursor.below(); } } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/compat/BaseMetalsCompat.java b/src/main/java/zone/moddev/mc/electricadvantage/compat/BaseMetalsCompat.java index 6c1592c..2ec2738 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/compat/BaseMetalsCompat.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/compat/BaseMetalsCompat.java @@ -35,10 +35,10 @@ public static ItemStack getCrusherRecipeOutput(World world, ItemStack input) { if (world == null || input == null || input.isEmpty()) return null; if (isLoaded()) { Inventory inventory = new Inventory(1); - inventory.setInventorySlotContents(0, input.copy()); + inventory.setItem(0, input.copy()); for (IRecipe candidate : world.getRecipeManager().getRecipes()) { if (candidate instanceof CrushingRecipe && ((CrushingRecipe) candidate).matches(inventory, world)) { - return candidate.getRecipeOutput().copy(); + return candidate.getResultItem().copy(); } } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/entities/HydroturbineEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/entities/HydroturbineEntity.java index a8af37b..03362a9 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/entities/HydroturbineEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/entities/HydroturbineEntity.java @@ -5,13 +5,13 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.EntityType; -import net.minecraft.fluid.IFluidState; +import net.minecraft.fluid.FluidState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.IPacket; import net.minecraftforge.fml.network.NetworkHooks; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import java.util.List; @@ -30,54 +30,54 @@ public class HydroturbineEntity extends net.minecraft.entity.Entity{ public HydroturbineEntity(EntityType type, World w) { super(type, w); - this.preventEntitySpawning = true; - roffset = w.rand.nextInt(8); + this.blocksBuilding = true; + roffset = w.random.nextInt(8); } public HydroturbineEntity(World w, BlockPos parentTileEntity) { - this(w, w.getTileEntity(parentTileEntity)); + this(w, w.getBlockEntity(parentTileEntity)); } public HydroturbineEntity(World w, TileEntity parentTileEntity) { this(zone.moddev.mc.electricadvantage.init.Entities.HYDROTURBINE, w); this.parent = parentTileEntity; - BlockPos p = parentTileEntity.getPos(); - this.setPosition(p.getX()+0.5, p.getY()-1, p.getZ()+0.5); + BlockPos p = parentTileEntity.getBlockPos(); + this.setPos(p.getX()+0.5, p.getY()-1, p.getZ()+0.5); } @Override - protected void registerData() { + protected void defineSynchedData() { // do nothing } @Override - public IPacket createSpawnPacket() { + public IPacket getAddEntityPacket() { return NetworkHooks.getEntitySpawningPacket(this); } @Override public void tick(){ super.tick(); - IFluidState fluidState = this.getEntityWorld().getFluidState(getPosition()); - Vec3d directionVector; + FluidState fluidState = this.getCommandSenderWorld().getFluidState(blockPosition()); + Vector3d directionVector; if(!fluidState.isEmpty()){ - directionVector = fluidState.getFlow(getEntityWorld(), getPosition()); + directionVector = fluidState.getFlow(getCommandSenderWorld(), blockPosition()); isSpinning = !(directionVector.x == 0 && directionVector.z == 0); } else { isSpinning = false; - directionVector = new Vec3d(0,0,0); + directionVector = new Vector3d(0,0,0); } - if(this.getEntityWorld().isRemote){ + if(this.getCommandSenderWorld().isClientSide){ // client-side only if(isSpinning){ rotation += DEGREES_PER_TICK; - this.rotationYaw = RADIANS_TO_DEGREES * (float)Math.atan2(-directionVector.z, directionVector.x) -90; + this.yRot = RADIANS_TO_DEGREES * (float)Math.atan2(-directionVector.z, directionVector.x) -90; } else { // do nothing } } else { // server-side only if(parent == null && parentCoord != null){ - parent = this.getEntityWorld().getTileEntity(parentCoord); + parent = this.getCommandSenderWorld().getBlockEntity(parentCoord); parentCoord = null; } if(parent == null || parent.isRemoved()){ @@ -89,18 +89,18 @@ public void tick(){ } generator.setActive(isSpinning); } - if(isSpinning && getEntityWorld().getGameTime() % 8 == roffset){ + if(isSpinning && getCommandSenderWorld().getGameTime() % 8 == roffset){ // slice-n-dice unfortunate souls caught in the blades - List victims = getEntityWorld().getEntitiesWithinAABB(LivingEntity.class, this.getBoundingBox()); + List victims = getCommandSenderWorld().getEntitiesOfClass(LivingEntity.class, this.getBoundingBox()); for(Entity e : victims){ - e.attackEntityFrom(Power.propeller_damage, PROPELLER_DAMAGE); + e.hurt(Power.propeller_damage, PROPELLER_DAMAGE); } } } } @Override - protected void readAdditional(CompoundNBT root) { + protected void readAdditionalSaveData(CompoundNBT root) { parent = null; parentCoord = null; if(root.contains("parentPos", 11)){ @@ -112,8 +112,8 @@ protected void readAdditional(CompoundNBT root) { } @Override - protected void writeAdditional(CompoundNBT root) { - BlockPos p = parent != null ? parent.getPos() : parentCoord; + protected void addAdditionalSaveData(CompoundNBT root) { + BlockPos p = parent != null ? parent.getBlockPos() : parentCoord; if(p != null){ int[] coords = new int[3]; coords[0] = p.getX(); diff --git a/src/main/java/zone/moddev/mc/electricadvantage/graphics/BufferedQuads.java b/src/main/java/zone/moddev/mc/electricadvantage/graphics/BufferedQuads.java index 4b93ab1..13d26d3 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/graphics/BufferedQuads.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/graphics/BufferedQuads.java @@ -13,7 +13,7 @@ final class BufferedQuads { private int count; BufferedQuads(MatrixStack matrices, IVertexBuilder buffer, int light, int overlay) { - this.transform = matrices.getLast(); + this.transform = matrices.last(); this.buffer = buffer; this.light = light; this.overlay = overlay; @@ -50,10 +50,10 @@ void endVertex() { nz /= length; } for (float[] vertex : vertices) { - buffer.pos(transform.getMatrix(), vertex[0], vertex[1], vertex[2]) - .color(255, 255, 255, 255).tex(vertex[3], vertex[4]) - .overlay(overlay).lightmap(light) - .normal(transform.getNormal(), nx, ny, nz).endVertex(); + buffer.vertex(transform.pose(), vertex[0], vertex[1], vertex[2]) + .color(255, 255, 255, 255).uv(vertex[3], vertex[4]) + .overlayCoords(overlay).uv2(light) + .normal(transform.normal(), nx, ny, nz).endVertex(); } count = 0; } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/graphics/ClientRegistration.java b/src/main/java/zone/moddev/mc/electricadvantage/graphics/ClientRegistration.java index c9e8038..b0b308d 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/graphics/ClientRegistration.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/graphics/ClientRegistration.java @@ -13,7 +13,7 @@ public final class ClientRegistration { private ClientRegistration() {} public static void onClientSetup(FMLClientSetupEvent event) { - RenderTypeLookup.setRenderLayer(Blocks.electric_track, RenderType.getCutout()); + RenderTypeLookup.setRenderLayer(Blocks.electric_track, RenderType.cutout()); ClientRegistry.bindTileEntityRenderer(Entities.ELECTRIC_DRILL, LaserDrillRenderer::new); ClientRegistry.bindTileEntityRenderer(Entities.LASER_TURRET, LaserTurretRenderer::new); RenderingRegistry.registerEntityRenderingHandler(Entities.HYDROTURBINE, HydroturbineRenderer::new); diff --git a/src/main/java/zone/moddev/mc/electricadvantage/graphics/ElectricRenderTypes.java b/src/main/java/zone/moddev/mc/electricadvantage/graphics/ElectricRenderTypes.java index 292ecc8..9bdc088 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/graphics/ElectricRenderTypes.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/graphics/ElectricRenderTypes.java @@ -12,11 +12,11 @@ private ElectricRenderTypes() { } static RenderType unshaded(ResourceLocation texture, boolean translucent) { - return RenderType.makeType("electricadvantage_unshaded", DefaultVertexFormats.ENTITY, - 7, 256, false, translucent, RenderType.State.getBuilder() - .texture(new TextureState(texture, false, false)) - .transparency(translucent ? TRANSLUCENT_TRANSPARENCY : NO_TRANSPARENCY) - .diffuseLighting(DIFFUSE_LIGHTING_DISABLED).cull(CULL_DISABLED) - .lightmap(LIGHTMAP_ENABLED).overlay(OVERLAY_ENABLED).build(false)); + return RenderType.create("electricadvantage_unshaded", DefaultVertexFormats.NEW_ENTITY, + 7, 256, false, translucent, RenderType.State.builder() + .setTextureState(new TextureState(texture, false, false)) + .setTransparencyState(translucent ? TRANSLUCENT_TRANSPARENCY : NO_TRANSPARENCY) + .setDiffuseLightingState(NO_DIFFUSE_LIGHTING).setCullState(NO_CULL) + .setLightmapState(LIGHTMAP).setOverlayState(OVERLAY).createCompositeState(false)); } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/graphics/HydroturbineRenderer.java b/src/main/java/zone/moddev/mc/electricadvantage/graphics/HydroturbineRenderer.java index eefef1f..b604fb5 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/graphics/HydroturbineRenderer.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/graphics/HydroturbineRenderer.java @@ -5,7 +5,7 @@ import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.Vector3f; +import net.minecraft.util.math.vector.Vector3f; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRendererManager; @@ -30,7 +30,7 @@ public void render(final HydroturbineEntity entity, final float entityYaw, final { final float pixel = 1.0f / 16; HydroturbineEntity e = (HydroturbineEntity)entity; - matrices.push(); + matrices.pushPose(); final float topHeight = 0.5f; final float bottomHeight = 0.375f-0.5f; final float radius = pixel; @@ -40,9 +40,9 @@ public void render(final HydroturbineEntity entity, final float entityYaw, final final float shaftMaxV = 1.0f; matrices.translate(0f, 0.5f, 0f); - matrices.rotate(Vector3f.YP.rotationDegrees(e.rotationYaw)); + matrices.mulPose(Vector3f.YP.rotationDegrees(e.yRot)); final BufferedQuads worldRenderer = new BufferedQuads(matrices, - buffers.getBuffer(RenderType.getEntitySolid(texture)), packedLight, OverlayTexture.NO_OVERLAY); + buffers.getBuffer(RenderType.entitySolid(texture)), packedLight, OverlayTexture.NO_OVERLAY); // render shaft worldRenderer.pos(+radius, bottomHeight, -radius).tex(shaftMinU,shaftMinV).endVertex(); @@ -173,14 +173,14 @@ public void render(final HydroturbineEntity entity, final float entityYaw, final worldRenderer.pos(cos3b*bladeOffset, sin3b*bladeOffset, depthDelta-axelLength).tex(bladeMinU,bladeMinV).endVertex(); // inner, leading - matrices.pop(); + matrices.popPose(); super.render(e, entityYaw, partialTick, matrices, buffers, packedLight); } } @Override - public ResourceLocation getEntityTexture(final HydroturbineEntity e) { + public ResourceLocation getTextureLocation(final HydroturbineEntity e) { return texture; } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/graphics/LaserDrillRenderer.java b/src/main/java/zone/moddev/mc/electricadvantage/graphics/LaserDrillRenderer.java index 7927ec1..552d9e2 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/graphics/LaserDrillRenderer.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/graphics/LaserDrillRenderer.java @@ -5,7 +5,7 @@ import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.Vector3f; +import net.minecraft.util.math.vector.Vector3f; import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.util.Direction; @@ -75,10 +75,10 @@ public void render(final ElectricDrillTileEntity e, final float partialTick, fin } } - matrices.push(); + matrices.pushPose(); matrices.translate(0.5f, 0.5f, 0.5f); - matrices.rotate(Vector3f.YP.rotationDegrees(rotY)); - matrices.rotate(Vector3f.XP.rotationDegrees(rotX)); + matrices.mulPose(Vector3f.YP.rotationDegrees(rotY)); + matrices.mulPose(Vector3f.XP.rotationDegrees(rotX)); final BufferedQuads worldRenderer = new BufferedQuads(matrices, buffers.getBuffer(beamType), 15 << 20 | 15 << 4, packedOverlay); @@ -118,7 +118,7 @@ public void render(final ElectricDrillTileEntity e, final float partialTick, fin worldRenderer.pos( x3, y4, z4).tex(laserU1, laserV0).endVertex(); worldRenderer.pos( x3, y3, z3).tex(laserU0, laserV0).endVertex(); - matrices.pop(); + matrices.popPose(); } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/graphics/LaserTurretRenderer.java b/src/main/java/zone/moddev/mc/electricadvantage/graphics/LaserTurretRenderer.java index aab7ae9..3840605 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/graphics/LaserTurretRenderer.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/graphics/LaserTurretRenderer.java @@ -5,7 +5,7 @@ import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.Vector3f; +import net.minecraft.util.math.vector.Vector3f; import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.util.ResourceLocation; @@ -57,10 +57,10 @@ public void render(final LaserTurretTileEntity e, final float partialTick, final float pitch = tickRemainder * e.rotOldPitch + partialTick * e.rotPitch; - matrices.push(); + matrices.pushPose(); matrices.translate(0.5f, 0.75f, 0.5f); - matrices.rotate(Vector3f.YP.rotationDegrees(yaw)); - matrices.rotate(Vector3f.XP.rotationDegrees(pitch)); + matrices.mulPose(Vector3f.YP.rotationDegrees(yaw)); + matrices.mulPose(Vector3f.XP.rotationDegrees(pitch)); BufferedQuads worldRenderer = new BufferedQuads(matrices, buffers.getBuffer(renderType), packedLight, packedOverlay); @@ -136,7 +136,7 @@ public void render(final LaserTurretTileEntity e, final float partialTick, final } - matrices.pop(); + matrices.popPose(); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/gui/ArcFurnaceGUI.java b/src/main/java/zone/moddev/mc/electricadvantage/gui/ArcFurnaceGUI.java index a6ae15a..e81dc24 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/gui/ArcFurnaceGUI.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/gui/ArcFurnaceGUI.java @@ -19,11 +19,11 @@ public ArcFurnaceGUI() { @Override public ItemStack onTake(PlayerEntity player, ItemStack stack) { - stack.onCrafting(player.getEntityWorld(), player, stack.getCount()); + stack.onCraftedBy(player.getCommandSenderWorld(), player, stack.getCount()); return super.onTake(player, stack); } @Override - public boolean isItemValid(ItemStack stack){ return false; } + public boolean mayPlace(ItemStack stack){ return false; } }); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/gui/FabricatorGUI.java b/src/main/java/zone/moddev/mc/electricadvantage/gui/FabricatorGUI.java index 6897eff..cfccfd0 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/gui/FabricatorGUI.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/gui/FabricatorGUI.java @@ -28,11 +28,11 @@ public FabricatorGUI() { @Override public ItemStack onTake(PlayerEntity player, ItemStack stack) { - stack.onCrafting(player.getEntityWorld(), player, stack.getCount()); + stack.onCraftedBy(player.getCommandSenderWorld(), player, stack.getCount()); return super.onTake(player, stack); } @Override - public boolean isItemValid(ItemStack stack){ return false; } + public boolean mayPlace(ItemStack stack){ return false; } }); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/gui/OvenGUI.java b/src/main/java/zone/moddev/mc/electricadvantage/gui/OvenGUI.java index 015aa4f..63ca61b 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/gui/OvenGUI.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/gui/OvenGUI.java @@ -18,11 +18,11 @@ public OvenGUI() { @Override public ItemStack onTake(PlayerEntity player, ItemStack stack) { - stack.onCrafting(player.getEntityWorld(), player, stack.getCount()); + stack.onCraftedBy(player.getCommandSenderWorld(), player, stack.getCount()); return super.onTake(player, stack); } @Override - public boolean isItemValid(ItemStack stack){ return false; } + public boolean mayPlace(ItemStack stack){ return false; } }); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/init/Blocks.java b/src/main/java/zone/moddev/mc/electricadvantage/init/Blocks.java index 6e3fd0c..e40e524 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/init/Blocks.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/init/Blocks.java @@ -113,7 +113,7 @@ private static Block add(Block block, String id) { for (Map.Entry entry : ALL_BLOCKS.entrySet()) { Item.Properties properties = new Item.Properties(); if (!"pump_pipe_electric".equals(entry.getKey()) && !"laser_turret_evil".equals(entry.getKey())) { - properties.group(ItemGroups.tab_powerAdvantage); + properties.tab(ItemGroups.tab_powerAdvantage); } BlockItem item = new BlockItem(entry.getValue(), properties); item.setRegistryName(ElectricAdvantage.MODID, entry.getKey()); diff --git a/src/main/java/zone/moddev/mc/electricadvantage/init/Entities.java b/src/main/java/zone/moddev/mc/electricadvantage/init/Entities.java index 8f62dfe..b9524f7 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/init/Entities.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/init/Entities.java @@ -72,9 +72,9 @@ public static void init() {} } @SubscribeEvent public static void registerEntities(RegistryEvent.Register> event) { - HYDROTURBINE = EntityType.Builder.create( + HYDROTURBINE = EntityType.Builder.of( HydroturbineEntity::new, EntityClassification.MISC) - .size(0.9375F, 0.9375F) + .sized(0.9375F, 0.9375F) .setTrackingRange(64).setUpdateInterval(1).setShouldReceiveVelocityUpdates(true) .build(ElectricAdvantage.MODID + ":hydroturbine"); HYDROTURBINE.setRegistryName(ElectricAdvantage.MODID, "hydroturbine"); @@ -84,7 +84,7 @@ public static void init() {} private static TileEntityType tile( RegistryEvent.Register> event, String id, Supplier factory, net.minecraft.block.Block... blocks) { - TileEntityType type = TileEntityType.Builder.create(factory, blocks).build(null); + TileEntityType type = TileEntityType.Builder.of(factory, blocks).build(null); type.setRegistryName(ElectricAdvantage.MODID, id); event.getRegistry().register(type); return type; diff --git a/src/main/java/zone/moddev/mc/electricadvantage/init/Items.java b/src/main/java/zone/moddev/mc/electricadvantage/init/Items.java index 92447ef..74aeed6 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/init/Items.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/init/Items.java @@ -61,7 +61,7 @@ static synchronized void initWithoutBlocks() { initialized = true; } - private static Item.Properties properties() { return new Item.Properties().group(ItemGroups.tab_powerAdvantage); } + private static Item.Properties properties() { return new Item.Properties().tab(ItemGroups.tab_powerAdvantage); } private static Item add(String id, Item item) { item.setRegistryName(ElectricAdvantage.MODID, id); allItems.put(id, item); diff --git a/src/main/java/zone/moddev/mc/electricadvantage/items/BatteryItem.java b/src/main/java/zone/moddev/mc/electricadvantage/items/BatteryItem.java index 633623c..1f17c2e 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/items/BatteryItem.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/items/BatteryItem.java @@ -21,7 +21,7 @@ public class BatteryItem extends net.minecraft.item.Item implements IRechargeabl private final NumberFormat nf; public BatteryItem(float capacity, Item.Properties properties){ - super(properties.maxStackSize(1)); + super(properties.stacksTo(1)); this.capacity = capacity; nf = NumberFormat.getInstance(); nf.setMaximumFractionDigits(0); @@ -95,15 +95,15 @@ public ConduitType getEnergyType(){ } @Override - public void addInformation(ItemStack stack, World world, List list, ITooltipFlag flag){ - super.addInformation(stack, world, list, flag); + public void appendHoverText(ItemStack stack, World world, List list, ITooltipFlag flag){ + super.appendHoverText(stack, world, list, flag); float max = getMaxEnergy(stack); if(max <= 0) return; // not a battery! float e = getEnergy(stack); list.add(new StringTextComponent(nf.format(100 * e / max) + "% ") - .appendSibling(new TranslationTextComponent("tooltip.battery.charge"))); + .append(new TranslationTextComponent("tooltip.battery.charge"))); list.add(new StringTextComponent("(" + nf.format(max) + "kJ ") - .appendSibling(new TranslationTextComponent("tooltip.battery.capacity")) - .appendText(")")); + .append(new TranslationTextComponent("tooltip.battery.capacity")) + .append(")")); } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricBatteryArrayBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricBatteryArrayBlock.java index 9b41de6..63de1b5 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricBatteryArrayBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricBatteryArrayBlock.java @@ -10,7 +10,7 @@ public ElectricBatteryArrayBlock(){ } @Override - public ElectricGeneratorTileEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public ElectricGeneratorTileEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new ElectricBatteryArrayTileEntity(); } @Override diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricBatteryArrayTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricBatteryArrayTileEntity.java index 855ffb2..1a92d85 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricBatteryArrayTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricBatteryArrayTileEntity.java @@ -114,7 +114,7 @@ public void powerUpdate(){ } protected boolean hasRedstoneSignal(){ - return getWorld().isBlockPowered(getPos()); + return getLevel().hasNeighborSignal(getBlockPos()); } @Override diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricCrusherBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricCrusherBlock.java index 5bc4000..ed5e003 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricCrusherBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricCrusherBlock.java @@ -9,7 +9,7 @@ public ElectricCrusherBlock(){ } @Override - public ElectricMachineTileEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public ElectricMachineTileEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new ElectricCrusherTileEntity(); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricCrusherTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricCrusherTileEntity.java index af1ea24..e6b34cb 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricCrusherTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricCrusherTileEntity.java @@ -43,7 +43,7 @@ public void tickUpdate(boolean isServerWorld) { smashTime[i]++; if(smashTime[i] >= totalSmashTime){ doCrush(i); - this.playSoundEffect(getPos().getX()+0.5, getPos().getY()+0.5, getPos().getZ()+0.5, SoundEvents.BLOCK_GRAVEL_BREAK, 0.5f, 1f); + this.playSoundEffect(getBlockPos().getX()+0.5, getBlockPos().getY()+0.5, getBlockPos().getZ()+0.5, SoundEvents.GRAVEL_BREAK, 0.5f, 1f); smashTime[i] = 0; } active = true; @@ -73,14 +73,14 @@ private static boolean areNotEqual(short[] a, short[] b){ private boolean canCrush(int slot){ ItemStack input = this.getInputSlot(slot); if(input == null) return false; - ItemStack output = BaseMetalsCompat.getCrusherRecipeOutput(getWorld(), input); + ItemStack output = BaseMetalsCompat.getCrusherRecipeOutput(getLevel(), input); if(output == null) return false; return this.hasSpaceForItemInOutputSlots(output); } private void doCrush(int slot){ ItemStack input = this.getInputSlot(slot); - ItemStack output = BaseMetalsCompat.getCrusherRecipeOutput(getWorld(), input); + ItemStack output = BaseMetalsCompat.getCrusherRecipeOutput(getLevel(), input); if(output == null) return; this.insertItemToOutputSlots(output); input.shrink(1); @@ -112,14 +112,14 @@ protected void saveTo(CompoundNBT tagRoot) { protected void loadFrom(CompoundNBT tagRoot) { ListNBT times = tagRoot.getList("smashTime", 2); for(int i = 0; i < numberOfInputSlots() && i < times.size(); i++){ - smashTime[i] = ((ShortNBT)times.get(i)).getShort(); + smashTime[i] = ((ShortNBT)times.get(i)).getAsShort(); } } @Override protected boolean isValidInputItem(ItemStack item) { if(item == null) return false; - return BaseMetalsCompat.hasCrusherRecipe(getWorld(), item); + return BaseMetalsCompat.hasCrusherRecipe(getLevel(), item); } private int[] dataArray = null; diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricDrillBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricDrillBlock.java index d2b25dc..626c3e2 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricDrillBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricDrillBlock.java @@ -33,49 +33,49 @@ public class ElectricDrillBlock extends GUIBlock implements ITypedConduit { private final ConduitType[] types = {Power.ELECTRIC_POWER}; public ElectricDrillBlock() { - super(Block.Properties.create(Material.PISTON).hardnessAndResistance(0.75F).variableOpacity().notSolid()); - setDefaultState(getStateContainer().getBaseState() - .with(ACTIVE, false) - .with(FACING, Direction.DOWN)); + super(Block.Properties.of(Material.PISTON).strength(0.75F).dynamicShape().noOcclusion()); + registerDefaultState(getStateDefinition().any() + .setValue(ACTIVE, false) + .setValue(FACING, Direction.DOWN)); } @Override - protected void fillStateContainer(StateContainer.Builder builder) { + protected void createBlockStateDefinition(StateContainer.Builder builder) { builder.add(ACTIVE, FACING); } @Override - public ElectricMachineTileEntity createNewTileEntity(IBlockReader world) { + public ElectricMachineTileEntity newBlockEntity(IBlockReader world) { return new ElectricDrillTileEntity(); } @Override - public void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState oldState, boolean isMoving) { - super.onBlockAdded(state, world, pos, oldState, isMoving); + public void onPlace(BlockState state, World world, BlockPos pos, BlockState oldState, boolean isMoving) { + super.onPlace(state, world, pos, oldState, isMoving); if (state.getBlock() == oldState.getBlock()) return; ConduitRegistry.getInstance().conduitBlockPlacedEvent( - world, world.dimension.getType().getId(), pos, Power.ELECTRIC_POWER); + world, pos, Power.ELECTRIC_POWER); } @Override - public void onReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean isMoving) { + public void onRemove(BlockState state, World world, BlockPos pos, BlockState newState, boolean isMoving) { if (state.getBlock() != newState.getBlock()) { ConduitRegistry.getInstance().conduitBlockRemovedEvent( - world, world.dimension.getType().getId(), pos, Power.ELECTRIC_POWER); - TileEntity tile = world.getTileEntity(pos); + world, pos, Power.ELECTRIC_POWER); + TileEntity tile = world.getBlockEntity(pos); if (tile instanceof IInventory) { - InventoryHelper.dropInventoryItems(world, pos, (IInventory) tile); - world.updateComparatorOutputLevel(pos, this); + InventoryHelper.dropContents(world, pos, (IInventory) tile); + world.updateNeighbourForOutputSignal(pos, this); } } - super.onReplaced(state, world, pos, newState, isMoving); + super.onRemove(state, world, pos, newState, isMoving); } @Override - public void onExplosionDestroy(World world, BlockPos pos, Explosion explosion) { + public void wasExploded(World world, BlockPos pos, Explosion explosion) { ConduitRegistry.getInstance().conduitBlockRemovedEvent( - world, world.dimension.getType().getId(), pos, Power.ELECTRIC_POWER); - super.onExplosionDestroy(world, pos, explosion); + world, pos, Power.ELECTRIC_POWER); + super.wasExploded(world, pos, explosion); } @Override @@ -100,40 +100,40 @@ public boolean canAcceptConnection(PowerConnectorContext connection) { @Override public BlockState getStateForPlacement(BlockItemUseContext context) { - return getDefaultState().with(FACING, context.getFace().getOpposite()); + return defaultBlockState().setValue(FACING, context.getClickedFace().getOpposite()); } @Override - public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, + public void setPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) { - if (stack.hasDisplayName()) { - TileEntity tile = world.getTileEntity(pos); + if (stack.hasCustomHoverName()) { + TileEntity tile = world.getBlockEntity(pos); if (tile instanceof PoweredEntity) { - ((PoweredEntity) tile).setCustomInventoryName(stack.getDisplayName().getString()); + ((PoweredEntity) tile).setCustomInventoryName(stack.getHoverName().getString()); } } } /** Decodes all six legacy facings; bit 3 is the active flag. */ public BlockState getStateFromLegacyMeta(int meta) { - return getDefaultState() - .with(FACING, Direction.byIndex(meta & 0x7)) - .with(ACTIVE, (meta & 0x8) != 0); + return defaultBlockState() + .setValue(FACING, Direction.from3DDataValue(meta & 0x7)) + .setValue(ACTIVE, (meta & 0x8) != 0); } public int getLegacyMetaFromState(BlockState state) { - return state.get(FACING).getIndex() | (state.get(ACTIVE) ? 0x8 : 0); + return state.getValue(FACING).get3DDataValue() | (state.getValue(ACTIVE) ? 0x8 : 0); } @Override - public int getComparatorInputOverride(BlockState state, World world, BlockPos pos) { - TileEntity tile = world.getTileEntity(pos); + public int getAnalogOutputSignal(BlockState state, World world, BlockPos pos) { + TileEntity tile = world.getBlockEntity(pos); return tile instanceof ElectricMachineTileEntity ? ((ElectricMachineTileEntity) tile).getComparatorOutput() : 0; } @Override - public boolean hasComparatorInputOverride(BlockState state) { + public boolean hasAnalogOutputSignal(BlockState state) { return true; } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricDrillTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricDrillTileEntity.java index 882c866..c9a1fd1 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricDrillTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricDrillTileEntity.java @@ -90,12 +90,12 @@ public void tickUpdate(boolean isServerWorld) { progress++; if(progress >= progressGoal){ // Mined it! - playSoundEffect(targetBlockCoord.getX()+0.5, targetBlockCoord.getY()+0.5, targetBlockCoord.getZ()+0.5, getWorld().getBlockState(targetBlockCoord).getSoundType().getPlaceSound(), 0.5f, 1f); - playSoundEffect(getPos().getX()+0.5, getPos().getY()+0.5, getPos().getZ()+0.5, SoundEvents.BLOCK_SAND_BREAK, 0.5f, 1f); + playSoundEffect(targetBlockCoord.getX()+0.5, targetBlockCoord.getY()+0.5, targetBlockCoord.getZ()+0.5, getLevel().getBlockState(targetBlockCoord).getSoundType().getPlaceSound(), 0.5f, 1f); + playSoundEffect(getBlockPos().getX()+0.5, getBlockPos().getY()+0.5, getBlockPos().getZ()+0.5, SoundEvents.SAND_BREAK, 0.5f, 1f); BlockPos[] targets = this.getArea(targetBlockCoord); for(int i = 0; i < targets.length; i++) if(canMine(targets[i])){ - getWorld().setBlockState(targets[i], net.minecraft.block.Blocks.AIR.getDefaultState(), 3); + getLevel().setBlock(targets[i], net.minecraft.block.Blocks.AIR.defaultBlockState(), 3); } for(ItemStack item : targetBlockItems){ addItem(item); @@ -134,7 +134,7 @@ public ItemStack addItem(ItemStack in){ private Direction trackDirection(){ for(Direction dir : Direction.values()){ - if(getWorld().getBlockState(getPos().offset(dir)).getBlock() == Blocks.electric_track){ + if(getLevel().getBlockState(getBlockPos().relative(dir)).getBlock() == Blocks.electric_track){ return dir; } } @@ -148,22 +148,22 @@ private boolean followTrack(){ // clone this block into neighboring block this.untargetBlock(); - World w = getWorld(); - BlockPos nextPos = getPos().offset(trackDir); - w.setBlockState(nextPos, w.getBlockState(getPos()), 2); - ElectricDrillTileEntity te = (ElectricDrillTileEntity)w.getTileEntity(nextPos); + World w = getLevel(); + BlockPos nextPos = getBlockPos().relative(trackDir); + w.setBlock(nextPos, w.getBlockState(getBlockPos()), 2); + ElectricDrillTileEntity te = (ElectricDrillTileEntity)w.getBlockEntity(nextPos); CompoundNBT dataTransfer = new CompoundNBT(); - this.write(dataTransfer); - te.read(dataTransfer); - te.setPos(nextPos); - te.validate(); + this.save(dataTransfer); + te.load(w.getBlockState(nextPos), dataTransfer); + te.setPosition(nextPos); + te.clearRemoved(); te.subtractEnergy(ENERGY_COST_MOVE, getEnergyType()); - te.markDirty(); + te.setChanged(); Arrays.fill(this.getInventory(), null); // replace this block with steam pipe - w.setBlockState(getPos().offset(getFacing()), zone.moddev.mc.poweradvantage.init.Blocks.steel_frame.getDefaultState()); - w.setBlockState(getPos(), Blocks.electric_conduit.getDefaultState(), 2); + w.setBlockAndUpdate(getBlockPos().relative(getFacing()), zone.moddev.mc.poweradvantage.init.Blocks.steel_frame.defaultBlockState()); + w.setBlock(getBlockPos(), Blocks.electric_conduit.defaultBlockState(), 2); return true; @@ -207,7 +207,7 @@ public void onDataFieldUpdate() { Direction f = getFacing(); - BlockPos n = getPos().offset(f); + BlockPos n = getBlockPos().relative(f); // manage drill bits and find next block if(redstone || this.getEnergy() <= 0){ @@ -225,9 +225,9 @@ public void onDataFieldUpdate() { break; } - if(getWorld().isAirBlock(n) || getWorld().getBlockState(n).getMaterial().isReplaceable()){ + if(getLevel().isEmptyBlock(n) || getLevel().getBlockState(n).getMaterial().isReplaceable()){ // this block is not worth mining, replace it - n = n.offset(f); + n = n.relative(f); if(n.getY() == 0 || n.getY() == 255){ hitEnd = true; break; @@ -248,7 +248,7 @@ public void onDataFieldUpdate() { boolean moved = followTrack(); if(moved){ zone.moddev.mc.poweradvantage.conduitnetwork.ConduitRegistry.getInstance() - .conduitBlockRemovedEvent(getWorld(), getWorld().dimension.getType().getId(), getPos(), getEnergyType()); + .conduitBlockRemovedEvent(getLevel(), getBlockPos(), getEnergyType()); return; } } @@ -257,7 +257,7 @@ public void onDataFieldUpdate() { // block revalidation BlockPos[] targets = getArea(targetBlockCoord); for(int i = 0; i < targets.length; i++){ - if(!getWorld().getBlockState(targets[i]).getBlock().equals(targetBlocks[i])){ + if(!getLevel().getBlockState(targets[i]).getBlock().equals(targetBlocks[i])){ // Block changed! Invalidate! untargetBlock(); flagSync = true; @@ -279,20 +279,20 @@ public void onDataFieldUpdate() { // push inventory to adjacent chest - BlockPos adj = getPos().offset(f.getOpposite()); - if(!redstone && !getWorld().isAirBlock(adj)){ + BlockPos adj = getBlockPos().relative(f.getOpposite()); + if(!redstone && !getLevel().isEmptyBlock(adj)){ inventoryTransfer(adj,f); } // fry any idiots who stand in the laser's path if(isActive() && targetBlocks != null && targetBlockCoord != null){ - BlockPos pos = getPos(); + BlockPos pos = getBlockPos(); AxisAlignedBB beamArea = new AxisAlignedBB(targetBlockCoord.getX(),targetBlockCoord.getY(),targetBlockCoord.getZ(), pos.getX()+1,pos.getY()+1,pos.getZ()+1); - List victims = getWorld().getEntitiesWithinAABB(LivingEntity.class, beamArea); + List victims = getLevel().getEntitiesOfClass(LivingEntity.class, beamArea); for(Entity e : victims){ - e.setFire(3); - e.attackEntityFrom(Power.laser_damage, 2f); + e.setSecondsOnFire(3); + e.hurt(Power.laser_damage, 2f); } } } @@ -304,7 +304,7 @@ public int getDrillLength(){ public void calculateDrillLength(){ if(this.isActive() && this.targetBlocks != null && this.targetBlockCoord != null){ - BlockPos pos = getPos(); + BlockPos pos = getBlockPos(); // distance calculation is taking a short-cut by assuming that 2 out of the 3 XYZ coordinates are identical laserLength = Math.abs((pos.getX() - targetBlockCoord.getX()) + (pos.getY() - targetBlockCoord.getY()) + (pos.getZ() - targetBlockCoord.getZ())); } else { @@ -321,11 +321,11 @@ private void targetBlock (BlockPos pos){ savedTargetStates = new ListNBT(); targetBlockItems = new ArrayList<>(targets.length); for(int i = 0; i < targets.length; i++){ - targetBlocks[i] = getWorld().getBlockState(targets[i]).getBlock(); - savedTargetStates.add(NBTUtil.writeBlockState(getWorld().getBlockState(targets[i]))); + targetBlocks[i] = getLevel().getBlockState(targets[i]).getBlock(); + savedTargetStates.add(NBTUtil.writeBlockState(getLevel().getBlockState(targets[i]))); progressGoal += this.getBlockStrength(targets[i]); - targetBlockItems.addAll(Block.getDrops(getWorld().getBlockState(targets[i]), - (ServerWorld) getWorld(), targets[i], getWorld().getTileEntity(targets[i]))); + targetBlockItems.addAll(Block.getDrops(getLevel().getBlockState(targets[i]), + (ServerWorld) getLevel(), targets[i], getLevel().getBlockEntity(targets[i]))); } deferred = false; } @@ -339,7 +339,7 @@ private void restoreTargetBlock(){ return; } for(int i = 0; i < targets.length; i++){ - if(!savedTargetStates.getCompound(i).equals(NBTUtil.writeBlockState(getWorld().getBlockState(targets[i])))){ + if(!savedTargetStates.getCompound(i).equals(NBTUtil.writeBlockState(getLevel().getBlockState(targets[i])))){ untargetBlock(); return; } @@ -356,18 +356,18 @@ private BlockPos[] getArea(BlockPos center){ switch(this.getFacing().getAxis()){ case X: a[1] = center.north(); - a[2] = center.down(); + a[2] = center.below(); a[3] = center.south(); - a[4] = center.up(); + a[4] = center.above(); a[5] = a[2].north(); a[6] = a[2].south(); a[7] = a[4].north(); a[8] = a[4].south(); break; case Z: - a[1] = center.down(); + a[1] = center.below(); a[2] = center.west(); - a[3] = center.up(); + a[3] = center.above(); a[4] = center.east(); a[5] = a[1].east(); a[6] = a[1].west(); @@ -411,7 +411,7 @@ public Direction getFacing(){ } private void updateFacing(){ final Direction old = facingCache; - facingCache = (Direction)getWorld().getBlockState(getPos()).get(ElectricDrillBlock.FACING); + facingCache = (Direction)getLevel().getBlockState(getBlockPos()).getValue(ElectricDrillBlock.FACING); if(old != null && old != facingCache){ untargetBlock(); this.sync(); @@ -420,26 +420,26 @@ private void updateFacing(){ private boolean canMine(BlockPos coord){ - BlockState bs = getWorld().getBlockState(coord); + BlockState bs = getLevel().getBlockState(coord); Block b = bs.getBlock(); // indestructable blocks have negative hardness - return !(b.getBlockHardness(bs, getWorld(), coord) < 0); + return !(bs.getDestroySpeed(getLevel(), coord) < 0); } private int getBlockStrength(BlockPos coord){ - if(getWorld().isAirBlock(coord)){ + if(getLevel().isEmptyBlock(coord)){ return 0; } - BlockState bs = getWorld().getBlockState(coord); + BlockState bs = getLevel().getBlockState(coord); Block block = bs.getBlock(); - return (int)(Math.max(MINING_TIME_FACTOR * block.getBlockHardness(bs, getWorld(), coord),0.5f * MINING_TIME_FACTOR)); + return (int)(Math.max(MINING_TIME_FACTOR * bs.getDestroySpeed(getLevel(), coord),0.5f * MINING_TIME_FACTOR)); } private void inventoryTransfer(BlockPos adj, Direction otherFace) { ItemStack[] inventory = this.getInventory(); - TileEntity te = getWorld().getTileEntity(adj); + TileEntity te = getLevel().getBlockEntity(adj); if(te instanceof IInventory ){ ISidedInventory inv = InventoryWrapper.wrap((IInventory)te); int[] accessibleSlots = inv.getSlotsForFace(otherFace); @@ -448,26 +448,26 @@ private void inventoryTransfer(BlockPos adj, Direction otherFace) { if(inventory[mySlot] == null || inventory[mySlot].isEmpty()) continue; for(int i = 0; i < accessibleSlots.length; i++){ int theirSlot = accessibleSlots[i]; - ItemStack theirItem = inv.getStackInSlot(theirSlot); - if(inv.canInsertItem(theirSlot, inventory[mySlot], otherFace)){ + ItemStack theirItem = inv.getItem(theirSlot); + if(inv.canPlaceItemThroughFace(theirSlot, inventory[mySlot], otherFace)){ if(theirItem == null || theirItem.isEmpty()){ ItemStack newItem = inventory[mySlot].copy(); newItem.setCount(1); - inv.setInventorySlotContents(theirSlot, newItem); + inv.setItem(theirSlot, newItem); inventory[mySlot].shrink(1); if(inventory[mySlot].isEmpty()) inventory[mySlot] = null; - inv.markDirty(); - this.markDirty(); + inv.setChanged(); + this.setChanged(); return; - } else if(ItemStack.areItemsEqual(theirItem, inventory[mySlot]) - && ItemStack.areItemStackTagsEqual(theirItem, inventory[mySlot]) + } else if(ItemStack.isSame(theirItem, inventory[mySlot]) + && ItemStack.tagMatches(theirItem, inventory[mySlot]) && theirItem.getCount() < theirItem.getMaxStackSize() - && theirItem.getCount() < inv.getInventoryStackLimit()){ + && theirItem.getCount() < inv.getMaxStackSize()){ theirItem.grow(1); inventory[mySlot].shrink(1); if(inventory[mySlot].isEmpty()) inventory[mySlot] = null; - inv.markDirty(); - this.markDirty(); + inv.setChanged(); + this.setChanged(); return; } } @@ -511,7 +511,7 @@ protected void loadFrom(CompoundNBT tagRoot) { int z = tagRoot.getInt("targetZ"); savedTargetStates = tagRoot.contains("TargetStates", 9) ? tagRoot.getList("TargetStates", 10).copy() : null; // Note: world object for tile entities is set AFTER loading them from NBT - if(getWorld() == null){ + if(getLevel() == null){ this.deferredTargetBlock(new BlockPos(x,y,z)); } else { this.deferredTargetBlock(new BlockPos(x,y,z)); @@ -527,11 +527,11 @@ protected boolean isValidInputItem(ItemStack item) { @Override protected void setActiveState(boolean active){ - BlockState oldState = getWorld().getBlockState(getPos()); + BlockState oldState = getLevel().getBlockState(getBlockPos()); if(oldState.getBlock() instanceof ElectricDrillBlock - && (Boolean)oldState.get(ElectricDrillBlock.ACTIVE) != active ){ - BlockState newState = oldState.with(ElectricDrillBlock.ACTIVE, active); - getWorld().setBlockState(getPos(), newState, 3); + && (Boolean)oldState.getValue(ElectricDrillBlock.ACTIVE) != active ){ + BlockState newState = oldState.setValue(ElectricDrillBlock.ACTIVE, active); + getLevel().setBlock(getBlockPos(), newState, 3); } } @Override @@ -541,7 +541,7 @@ protected void setPowerState(boolean powered){ @Override public boolean isActive(){ - return isPowered() && (!this.hasRedstoneSignal() && (this.getEnergy() > 0 || (Boolean)getWorld().getBlockState(getPos()).get(ElectricDrillBlock.ACTIVE))); + return isPowered() && (!this.hasRedstoneSignal() && (this.getEnergy() > 0 || (Boolean)getLevel().getBlockState(getBlockPos()).getValue(ElectricDrillBlock.ACTIVE))); } // Helps with laser rendering @@ -549,7 +549,7 @@ public boolean isActive(){ @OnlyIn(Dist.CLIENT) public AxisAlignedBB getRenderBoundingBox() { - return new AxisAlignedBB(getPos().add(-renderRange, -renderRange, -renderRange), getPos().add(renderRange, renderRange, renderRange)); + return new AxisAlignedBB(getBlockPos().offset(-renderRange, -renderRange, -renderRange), getBlockPos().offset(renderRange, renderRange, renderRange)); //return super.INFINITE_EXTENT_AABB; } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFabricatorBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFabricatorBlock.java index 36e4e32..900d894 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFabricatorBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFabricatorBlock.java @@ -5,7 +5,7 @@ public class ElectricFabricatorBlock extends ElectricMachineBlock{ @Override - public ElectricMachineTileEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public ElectricMachineTileEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new ElectricFabricatorTileEntity(); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFabricatorTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFabricatorTileEntity.java index c981b67..813cec3 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFabricatorTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFabricatorTileEntity.java @@ -73,7 +73,7 @@ public void tickUpdate(boolean isServerWorld) { case CRAFT_COMPLETE:{ if(canCraft()) { doCraft(); - playSoundEffect(getPos().getX() + 0.5, getPos().getY() + 0.5, getPos().getZ() + 0.5, SoundEvents.BLOCK_ANVIL_LAND, 0.15f, 1f); + playSoundEffect(getBlockPos().getX() + 0.5, getBlockPos().getY() + 0.5, getBlockPos().getZ() + 0.5, SoundEvents.ANVIL_LAND, 0.15f, 1f); } state = FSM.READY; break; @@ -119,7 +119,7 @@ private boolean canCraft(){ // then check if it is craftable from our input inventory AtomicReference output = new AtomicReference<>(); ItemStack[] inv = Arrays.copyOf(getInventory(), this.numberOfInputSlots()); - SerializedInventory result = RecipeDeconstructor.getInstance().attemptToCraft(getWorld(), referenceItem, + SerializedInventory result = RecipeDeconstructor.getInstance().attemptToCraft(getLevel(), referenceItem, SerializedInventory.serialize(inv), output); if(result == null || isEmptyStack(output.get())) return false; // then check if there is space in the output buffer @@ -134,7 +134,7 @@ private void doCraft(){ // assuming that canCraft() was already used to check validity AtomicReference output = new AtomicReference<>(); ItemStack[] inv = Arrays.copyOf(getInventory(), this.numberOfInputSlots()); - SerializedInventory result = RecipeDeconstructor.getInstance().attemptToCraft(getWorld(), referenceItem, + SerializedInventory result = RecipeDeconstructor.getInstance().attemptToCraft(getLevel(), referenceItem, SerializedInventory.serialize(inv), output); this.insertItemToOutputSlots(output.get()); List newInventory = result.deserialize(); diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFurnaceBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFurnaceBlock.java index b7554c5..0b670c3 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFurnaceBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFurnaceBlock.java @@ -9,7 +9,7 @@ public ElectricFurnaceBlock(){ } @Override - public ElectricMachineTileEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public ElectricMachineTileEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new ElectricFurnaceTileEntity(); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFurnaceTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFurnaceTileEntity.java index 5443c02..7b18f0f 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFurnaceTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricFurnaceTileEntity.java @@ -108,7 +108,7 @@ protected void saveTo(CompoundNBT tagRoot) { protected void loadFrom(CompoundNBT tagRoot) { ListNBT burnTimes = tagRoot.getList("cookTime", 2); for(int i = 0; i < numberOfInputSlots() && i < burnTimes.size(); i++){ - burnTime[i] = ((ShortNBT)burnTimes.get(i)).getShort(); + burnTime[i] = ((ShortNBT)burnTimes.get(i)).getAsShort(); } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricGeneratorBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricGeneratorBlock.java index 432df8c..10dbbf1 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricGeneratorBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricGeneratorBlock.java @@ -34,53 +34,53 @@ protected ElectricGeneratorBlock(Block.Properties properties) { } private void initializeDefaultState() { - setDefaultState(getStateContainer().getBaseState() - .with(ACTIVE, false) - .with(FACING, Direction.NORTH)); + registerDefaultState(getStateDefinition().any() + .setValue(ACTIVE, false) + .setValue(FACING, Direction.NORTH)); } @Override - protected void fillStateContainer(StateContainer.Builder builder) { + protected void createBlockStateDefinition(StateContainer.Builder builder) { builder.add(ACTIVE, FACING); } /** Decodes the 1.10/1.12 metadata used by world migration fixtures. */ public BlockState getStateFromLegacyMeta(int meta) { - Direction facing = Direction.byIndex(meta & 0x7); + Direction facing = Direction.from3DDataValue(meta & 0x7); if (facing.getAxis() == Direction.Axis.Y) facing = Direction.NORTH; - return getDefaultState().with(FACING, facing).with(ACTIVE, (meta & 0x8) != 0); + return defaultBlockState().setValue(FACING, facing).setValue(ACTIVE, (meta & 0x8) != 0); } public int getLegacyMetaFromState(BlockState state) { - return state.get(FACING).getIndex() | (state.get(ACTIVE) ? 0x8 : 0); + return state.getValue(FACING).get3DDataValue() | (state.getValue(ACTIVE) ? 0x8 : 0); } @Override - public abstract ElectricGeneratorTileEntity createNewTileEntity(IBlockReader world); + public abstract ElectricGeneratorTileEntity newBlockEntity(IBlockReader world); @Override - public int getComparatorInputOverride(BlockState state, World world, BlockPos pos) { - TileEntity tile = world.getTileEntity(pos); + public int getAnalogOutputSignal(BlockState state, World world, BlockPos pos) { + TileEntity tile = world.getBlockEntity(pos); return tile instanceof ElectricGeneratorTileEntity ? ((ElectricGeneratorTileEntity) tile).getComparatorOutput() : 0; } @Override - public boolean hasComparatorInputOverride(BlockState state) { + public boolean hasAnalogOutputSignal(BlockState state) { return true; } @Override - public void onReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean isMoving) { + public void onRemove(BlockState state, World world, BlockPos pos, BlockState newState, boolean isMoving) { if (state.getBlock() != newState.getBlock()) { - TileEntity tile = world.getTileEntity(pos); + TileEntity tile = world.getBlockEntity(pos); if (tile instanceof IInventory) { - InventoryHelper.dropInventoryItems(world, pos, (IInventory) tile); - ((IInventory) tile).clear(); - world.updateComparatorOutputLevel(pos, this); + InventoryHelper.dropContents(world, pos, (IInventory) tile); + ((IInventory) tile).clearContent(); + world.updateNeighbourForOutputSignal(pos, this); } } - super.onReplaced(state, world, pos, newState, isMoving); + super.onRemove(state, world, pos, newState, isMoving); } @Override diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricGeneratorTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricGeneratorTileEntity.java index 90dcedc..fa5b34f 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricGeneratorTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricGeneratorTileEntity.java @@ -51,7 +51,7 @@ public ElectricGeneratorTileEntity(TileEntityType tileType, String name,int n public void powerUpdate(){ super.powerUpdate(); - redstone = getWorld().isBlockPowered(getPos()); + redstone = getLevel().hasNeighborSignal(getBlockPos()); if(oldEnergy != this.getEnergy(Power.ELECTRIC_POWER)){ this.sync(); @@ -64,27 +64,27 @@ protected boolean hasRedstoneSignal(){ protected void setActive(boolean active){ - BlockState old = getWorld().getBlockState(getPos()); + BlockState old = getLevel().getBlockState(getBlockPos()); if(old.getBlock() instanceof ElectricGeneratorBlock - && (Boolean)old.get(ElectricGeneratorBlock.ACTIVE) != active){ - getWorld().setBlockState(getPos(), old.with(ElectricGeneratorBlock.ACTIVE, active), 3); + && (Boolean)old.getValue(ElectricGeneratorBlock.ACTIVE) != active){ + getLevel().setBlock(getBlockPos(), old.setValue(ElectricGeneratorBlock.ACTIVE, active), 3); } } protected void playSoundEffect(double x, double y, double z, SoundEvent sound, float volume, float pitch){ - if(getWorld().isRemote) return; + if(getLevel().isClientSide) return; final double range = 16; - List players = getWorld().getEntitiesWithinAABB(ServerPlayerEntity.class, new AxisAlignedBB( + List players = getLevel().getEntitiesOfClass(ServerPlayerEntity.class, new AxisAlignedBB( x - range, y - range, z - range, x + range, y + range, z + range)); for(ServerPlayerEntity player : players){ - player.connection.sendPacket(new SPlaySoundPacket(sound.getRegistryName(), SoundCategory.BLOCKS, - new net.minecraft.util.math.Vec3d(x, y, z), volume, pitch)); + player.connection.send(new SPlaySoundPacket(sound.getRegistryName(), SoundCategory.BLOCKS, + new net.minecraft.util.math.vector.Vector3d(x, y, z), volume, pitch)); } } public boolean isActive(){ - return (Boolean)getWorld().getBlockState(getPos()).get(ElectricGeneratorBlock.ACTIVE); + return (Boolean)getLevel().getBlockState(getBlockPos()).getValue(ElectricGeneratorBlock.ACTIVE); } @Override @@ -120,12 +120,12 @@ protected ItemStack[] getInventory() { @Override - public boolean canInsertItem(final int slot, final ItemStack srcItem, final Direction side) { + public boolean canPlaceItemThroughFace(final int slot, final ItemStack srcItem, final Direction side) { return isValidInputItem(srcItem) && isInArray(slot,inputSlots); } @Override - public boolean isItemValidForSlot(final int slot, final ItemStack srcItem) { + public boolean canPlaceItem(final int slot, final ItemStack srcItem) { return isValidInputItem(srcItem) && isInArray(slot,inputSlots); } @@ -168,20 +168,20 @@ public int getComparatorOutput(){ @Override - public CompoundNBT write(CompoundNBT tagRoot){ - super.write(tagRoot); + public CompoundNBT save(CompoundNBT tagRoot){ + super.save(tagRoot); saveTo(tagRoot); return tagRoot; } @Override - public void read(CompoundNBT tagRoot){ - super.read(tagRoot); + public void load(BlockState state, CompoundNBT tagRoot){ + super.load(state, tagRoot); loadFrom(tagRoot); } protected abstract void saveTo(CompoundNBT tagRoot); protected abstract void loadFrom(CompoundNBT tagRoot); - @Override public int getInventoryStackLimit(){return 64;} + @Override public int getMaxStackSize(){return 64;} } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricMachineBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricMachineBlock.java index c8a7280..86a8968 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricMachineBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricMachineBlock.java @@ -35,10 +35,10 @@ protected ElectricMachineBlock(Block.Properties properties) { } private void initializeDefaultState() { - setDefaultState(getStateContainer().getBaseState() - .with(ACTIVE, false) - .with(POWERED, false) - .with(FACING, Direction.NORTH)); + registerDefaultState(getStateDefinition().any() + .setValue(ACTIVE, false) + .setValue(POWERED, false) + .setValue(FACING, Direction.NORTH)); } public ElectricMachineBlock(Material material) { @@ -46,23 +46,23 @@ public ElectricMachineBlock(Material material) { } @Override - protected void fillStateContainer(StateContainer.Builder builder) { + protected void createBlockStateDefinition(StateContainer.Builder builder) { builder.add(ACTIVE, FACING, POWERED); } /** Decodes the 1.10/1.12 metadata used by world migration fixtures. */ public BlockState getStateFromLegacyMeta(int meta) { - return getDefaultState() - .with(FACING, metaToFacing(meta)) - .with(ACTIVE, (meta & 0x4) != 0) - .with(POWERED, (meta & 0x8) != 0); + return defaultBlockState() + .setValue(FACING, metaToFacing(meta)) + .setValue(ACTIVE, (meta & 0x4) != 0) + .setValue(POWERED, (meta & 0x8) != 0); } /** Encodes the legacy metadata layout for migration tests. */ public int getLegacyMetaFromState(BlockState state) { - int meta = facingToMeta(state.get(FACING)); - if (state.get(ACTIVE)) meta |= 0x4; - if (state.get(POWERED)) meta |= 0x8; + int meta = facingToMeta(state.getValue(FACING)); + if (state.getValue(ACTIVE)) meta |= 0x4; + if (state.getValue(POWERED)) meta |= 0x8; return meta; } @@ -85,31 +85,31 @@ private static Direction metaToFacing(int meta) { } @Override - public abstract ElectricMachineTileEntity createNewTileEntity(IBlockReader world); + public abstract ElectricMachineTileEntity newBlockEntity(IBlockReader world); @Override - public int getComparatorInputOverride(BlockState state, World world, BlockPos pos) { - TileEntity tile = world.getTileEntity(pos); + public int getAnalogOutputSignal(BlockState state, World world, BlockPos pos) { + TileEntity tile = world.getBlockEntity(pos); return tile instanceof ElectricMachineTileEntity ? ((ElectricMachineTileEntity) tile).getComparatorOutput() : 0; } @Override - public boolean hasComparatorInputOverride(BlockState state) { + public boolean hasAnalogOutputSignal(BlockState state) { return true; } @Override - public void onReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean isMoving) { + public void onRemove(BlockState state, World world, BlockPos pos, BlockState newState, boolean isMoving) { if (state.getBlock() != newState.getBlock()) { - TileEntity tile = world.getTileEntity(pos); + TileEntity tile = world.getBlockEntity(pos); if (tile instanceof IInventory) { - InventoryHelper.dropInventoryItems(world, pos, (IInventory) tile); - ((IInventory) tile).clear(); - world.updateComparatorOutputLevel(pos, this); + InventoryHelper.dropContents(world, pos, (IInventory) tile); + ((IInventory) tile).clearContent(); + world.updateNeighbourForOutputSignal(pos, this); } } - super.onReplaced(state, world, pos, newState, isMoving); + super.onRemove(state, world, pos, newState, isMoving); } @Override diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricMachineTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricMachineTileEntity.java index 9677d1a..bff7661 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricMachineTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricMachineTileEntity.java @@ -78,7 +78,7 @@ public ElectricMachineTileEntity(TileEntityType tileType, String name,int num public void powerUpdate(){ super.powerUpdate(); - redstone = getWorld().isBlockPowered(getPos()); + redstone = getLevel().hasNeighborSignal(getBlockPos()); this.setPowerState(this.isPowered()); @@ -104,25 +104,25 @@ protected boolean hasRedstoneSignal(){ protected void setActiveState(boolean active){ - BlockState oldState = getWorld().getBlockState(getPos()); + BlockState oldState = getLevel().getBlockState(getBlockPos()); if(oldState.getBlock() instanceof ElectricMachineBlock - && (Boolean)oldState.get(ElectricMachineBlock.ACTIVE) != active ){ - BlockState newState = oldState.with(ElectricMachineBlock.ACTIVE, active); - getWorld().setBlockState(getPos(), newState, 3); + && (Boolean)oldState.getValue(ElectricMachineBlock.ACTIVE) != active ){ + BlockState newState = oldState.setValue(ElectricMachineBlock.ACTIVE, active); + getLevel().setBlock(getBlockPos(), newState, 3); } } protected void setPowerState(boolean powered){ - BlockState oldState = getWorld().getBlockState(getPos()); + BlockState oldState = getLevel().getBlockState(getBlockPos()); if(oldState.getBlock() instanceof ElectricMachineBlock - && (Boolean)oldState.get(ElectricMachineBlock.POWERED) != powered ){ - BlockState newState = oldState.with(ElectricMachineBlock.POWERED, powered); - getWorld().setBlockState(getPos(), newState, 3); + && (Boolean)oldState.getValue(ElectricMachineBlock.POWERED) != powered ){ + BlockState newState = oldState.setValue(ElectricMachineBlock.POWERED, powered); + getLevel().setBlock(getBlockPos(), newState, 3); } } public boolean isActive(){ - return isPowered() && (!this.hasRedstoneSignal() && (this.getEnergy(Power.ELECTRIC_POWER) > 0 || (Boolean)getWorld().getBlockState(getPos()).get(ElectricMachineBlock.ACTIVE))); + return isPowered() && (!this.hasRedstoneSignal() && (this.getEnergy(Power.ELECTRIC_POWER) > 0 || (Boolean)getLevel().getBlockState(getBlockPos()).getValue(ElectricMachineBlock.ACTIVE))); } public abstract boolean isPowered(); @@ -204,40 +204,40 @@ protected static ItemStack copyStackOrNull(ItemStack stack) { protected static boolean areItemsEqualNullable(ItemStack left, ItemStack right) { if(isEmptyStack(left)) return isEmptyStack(right); if(isEmptyStack(right)) return false; - return ItemStack.areItemsEqual(left, right); + return ItemStack.isSame(left, right); } protected static boolean areItemStacksEqualNullable(ItemStack left, ItemStack right) { if(isEmptyStack(left)) return isEmptyStack(right); if(isEmptyStack(right)) return false; - return ItemStack.areItemStacksEqual(left, right); + return ItemStack.matches(left, right); } public abstract float[] getProgress(); protected ItemStack getSmeltingResult(ItemStack input) { - if (isEmptyStack(input) || getWorld() == null) return ItemStack.EMPTY; + if (isEmptyStack(input) || getLevel() == null) return ItemStack.EMPTY; Inventory inventory = new Inventory(1); - inventory.setInventorySlotContents(0, input); - return getWorld().getRecipeManager().getRecipe(IRecipeType.SMELTING, inventory, getWorld()) - .map(recipe -> recipe.getCraftingResult(inventory)).orElse(ItemStack.EMPTY); + inventory.setItem(0, input); + return getLevel().getRecipeManager().getRecipeFor(IRecipeType.SMELTING, inventory, getLevel()) + .map(recipe -> recipe.assemble(inventory)).orElse(ItemStack.EMPTY); } @Override - public CompoundNBT write(CompoundNBT tagRoot){ - super.write(tagRoot); + public CompoundNBT save(CompoundNBT tagRoot){ + super.save(tagRoot); saveTo(tagRoot); return tagRoot; } @Override public CompoundNBT getUpdateTag() { - return write(new CompoundNBT()); + return save(new CompoundNBT()); } @Override - public void read(CompoundNBT tagRoot){ - super.read(tagRoot); + public void load(BlockState state, CompoundNBT tagRoot){ + super.load(state, tagRoot); loadFrom(tagRoot); } @@ -251,7 +251,7 @@ public int[] getSlotsForFace(Direction side) { } @Override - public boolean canExtractItem(final int slot, final ItemStack targetItem, final Direction side) { + public boolean canTakeItemThroughFace(final int slot, final ItemStack targetItem, final Direction side) { return isInArray(slot,outputSlots); } @@ -261,10 +261,10 @@ public boolean hasSpaceForItemInOutputSlots(ItemStack stack){ for(int slot = 0; slot < numberOfOutputSlots(); slot++){ ItemStack dest = getOutputSlot(slot); if(isEmptyStack(dest)) return true; - int stackLimit = Math.min(dest.getMaxStackSize(), this.getInventoryStackLimit()); + int stackLimit = Math.min(dest.getMaxStackSize(), this.getMaxStackSize()); if(dest.getCount() >= stackLimit) continue; int combinedStackSize = item.getCount() + dest.getCount(); - if(ItemStack.areItemsEqual(item, dest) ){ + if(ItemStack.isSame(item, dest) ){ if(combinedStackSize <= stackLimit){ return true; } else if (item.getCount() <= stackLimit) { @@ -281,10 +281,10 @@ public boolean hasSpaceForItemInInputSlots(ItemStack stack){ for(int slot = 0; slot < numberOfInputSlots(); slot++){ ItemStack dest = getInputSlot(slot); if(isEmptyStack(dest)) return true; - int stackLimit = Math.min(dest.getMaxStackSize(), this.getInventoryStackLimit()); + int stackLimit = Math.min(dest.getMaxStackSize(), this.getMaxStackSize()); if(dest.getCount() >= stackLimit) continue; int combinedStackSize = item.getCount() + dest.getCount(); - if(ItemStack.areItemsEqual(item, dest) ){ + if(ItemStack.isSame(item, dest) ){ if(combinedStackSize <= stackLimit){ return true; } else if (item.getCount() <= stackLimit) { @@ -296,12 +296,12 @@ public boolean hasSpaceForItemInInputSlots(ItemStack stack){ } @Override - public boolean canInsertItem(final int slot, final ItemStack srcItem, final Direction side) { + public boolean canPlaceItemThroughFace(final int slot, final ItemStack srcItem, final Direction side) { return isValidInputItem(srcItem) && isInArray(slot,inputSlots); } @Override - public boolean isItemValidForSlot(final int slot, final ItemStack srcItem) { + public boolean canPlaceItem(final int slot, final ItemStack srcItem) { return isValidInputItem(srcItem) && isInArray(slot,inputSlots); } @@ -324,8 +324,8 @@ public ItemStack insertItemToInputSlots(ItemStack itemStack){ // empty slot this.setInputSlot(slot,itemStack); return null; - } else if(ItemStack.areItemsEqual(itemStack, slotContent)){ - int stackLimit = Math.min(slotContent.getMaxStackSize(), this.getInventoryStackLimit()); + } else if(ItemStack.isSame(itemStack, slotContent)){ + int stackLimit = Math.min(slotContent.getMaxStackSize(), this.getMaxStackSize()); // found slot with same item if(slotContent.getCount() < stackLimit){ // increase stack @@ -341,14 +341,14 @@ public ItemStack insertItemToInputSlots(ItemStack itemStack){ } protected void playSoundEffect(double x, double y, double z, SoundEvent sound, float volume, float pitch){ - if(getWorld().isRemote) return; + if(getLevel().isClientSide) return; final double range = 16; - List players = getWorld().getEntitiesWithinAABB(ServerPlayerEntity.class, new AxisAlignedBB( + List players = getLevel().getEntitiesOfClass(ServerPlayerEntity.class, new AxisAlignedBB( x - range, y - range, z - range, x + range, y + range, z + range)); for(ServerPlayerEntity player : players){ - player.connection.sendPacket(new SPlaySoundPacket(sound.getRegistryName(), SoundCategory.BLOCKS, - new net.minecraft.util.math.Vec3d(x, y, z), volume, pitch)); + player.connection.send(new SPlaySoundPacket(sound.getRegistryName(), SoundCategory.BLOCKS, + new net.minecraft.util.math.vector.Vector3d(x, y, z), volume, pitch)); } } @@ -362,8 +362,8 @@ public ItemStack insertItemToOutputSlots(ItemStack itemStack){ // empty slot this.setOutputSlot(slot,itemStack); return null; - } else if(ItemStack.areItemsEqual(itemStack, slotContent)){ - int stackLimit = Math.min(slotContent.getMaxStackSize(), this.getInventoryStackLimit()); + } else if(ItemStack.isSame(itemStack, slotContent)){ + int stackLimit = Math.min(slotContent.getMaxStackSize(), this.getMaxStackSize()); // found slot with same item if(slotContent.getCount() < stackLimit){ // increase stack @@ -417,7 +417,7 @@ public float subtractEnergy(float amount){ public ConduitType getEnergyType() {return Power.ELECTRIC_POWER;} - @Override public int getInventoryStackLimit(){return 64;} + @Override public int getMaxStackSize(){return 64;} @Override diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricOvenBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricOvenBlock.java index f53ad23..1e28d8f 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricOvenBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricOvenBlock.java @@ -9,7 +9,7 @@ public ElectricOvenBlock(){ } @Override - public ElectricMachineTileEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public ElectricMachineTileEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new ElectricOvenTileEntity(); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricOvenTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricOvenTileEntity.java index e91c176..4ef0441 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricOvenTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricOvenTileEntity.java @@ -35,7 +35,7 @@ public void tickUpdate(boolean isServerWorld) { setInputSlot(0,null); } progress = 0; - playSoundEffect(getPos().getX()+0.5, getPos().getY()+0.5, getPos().getZ()+0.5, SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, 0.5f, 1.0f); + playSoundEffect(getBlockPos().getX()+0.5, getBlockPos().getY()+0.5, getBlockPos().getZ()+0.5, SoundEvents.EXPERIENCE_ORB_PICKUP, 0.5f, 1.0f); } active = true; } else { @@ -52,7 +52,7 @@ public void tickUpdate(boolean isServerWorld) { public static boolean isFoodItem(ItemStack item){ if(item == null) return false; Item i = item.getItem(); - return !item.isEmpty() && i.isFood(); + return !item.isEmpty() && i.isEdible(); } public boolean becomesFoodItem(ItemStack item){ diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricPumpBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricPumpBlock.java index 168ed04..fcd654e 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricPumpBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricPumpBlock.java @@ -14,7 +14,7 @@ public class ElectricPumpBlock extends ElectricMachineBlock{ @Override - public ElectricMachineTileEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public ElectricMachineTileEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new ElectricPumpTileEntity(); } @@ -24,27 +24,27 @@ public ElectricMachineTileEntity createNewTileEntity(net.minecraft.world.IBlockR * This method is called whenever the block is placed into the world */ @Override - public void onReplaced(BlockState state, World w, BlockPos coord, BlockState newState, boolean isMoving) { + public void onRemove(BlockState state, World w, BlockPos coord, BlockState newState, boolean isMoving) { if (state.getBlock() != newState.getBlock()) destroyPipe(w, coord); - super.onReplaced(state, w, coord, newState, isMoving); + super.onRemove(state, w, coord, newState, isMoving); } /** * This method is called when the block is destroyed by an explosion. */ @Override - public void onExplosionDestroy(World w, BlockPos coord, Explosion boom){ + public void wasExploded(World w, BlockPos coord, Explosion boom){ destroyPipe(w,coord); - super.onExplosionDestroy(w, coord, boom); + super.wasExploded(w, coord, boom); } private void destroyPipe(World w, BlockPos coord) { - if(w.isRemote) return; + if(w.isClientSide) return; // destroy connected drill bits - BlockPos c = coord.down(); + BlockPos c = coord.below(); while(c.getY() > 0 && w.getBlockState(c).getBlock() == Blocks.pump_pipe_electric){ - w.setBlockState(c, net.minecraft.block.Blocks.AIR.getDefaultState()); - c = c.down(); + w.setBlockAndUpdate(c, net.minecraft.block.Blocks.AIR.defaultBlockState()); + c = c.below(); } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricPumpTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricPumpTileEntity.java index 710c41d..8e5cc33 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricPumpTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricPumpTileEntity.java @@ -57,50 +57,50 @@ public void tickUpdate(boolean isServerWorld) { if(!hasRedstoneSignal()){ if(timeUntilNextPump > 0) timeUntilNextPump--; if(timeUntilNextPump == 0 && getTank().getFluidAmount() <= 0){ - World w = getWorld(); + World w = getLevel(); boolean success = false; - BlockPos target = this.getPos().down(); + BlockPos target = this.getBlockPos().below(); while(target.getY() > 0 && w.getBlockState(target).getBlock() == zone.moddev.mc.electricadvantage.init.Blocks.pump_pipe_electric){ - target = target.down(); + target = target.below(); } - if(target.getY() > 0 && w.isAirBlock(target) && getEnergy() >= ENERGY_COST_PIPE){ + if(target.getY() > 0 && w.isEmptyBlock(target) && getEnergy() >= ENERGY_COST_PIPE){ // place pipe - w.setBlockState(target, zone.moddev.mc.electricadvantage.init.Blocks.pump_pipe_electric.getDefaultState()); + w.setBlockAndUpdate(target, zone.moddev.mc.electricadvantage.init.Blocks.pump_pipe_electric.defaultBlockState()); this.subtractEnergy(ENERGY_COST_PIPE, Power.ELECTRIC_POWER); timeUntilNextPump = PIPE_INTERVAL; - playSoundEffect(target.getX()+0.5, target.getY()+0.5, target.getZ()+0.5, SoundEvents.BLOCK_STONE_STEP, 0.3f, 1f); + playSoundEffect(target.getX()+0.5, target.getY()+0.5, target.getZ()+0.5, SoundEvents.STONE_STEP, 0.3f, 1f); } else { // pump fluids BlockPos fluidSource = null; Set searchSpace = new HashSet<>(limit + 1); // pre-allocate max memory usage - fluidSource = scan(searchSpace,target.down(), limit); + fluidSource = scan(searchSpace,target.below(), limit); if(fluidSource == null) fluidSource = scan(searchSpace,target.north(), limit); if(fluidSource == null) fluidSource = scan(searchSpace,target.west(), limit); if(fluidSource == null) fluidSource = scan(searchSpace,target.south(), limit); if(fluidSource == null) fluidSource = scan(searchSpace,target.east(), limit); if(fluidSource != null){ - float cost = ENERGY_COST_PUMP+ENERGY_COST_VERTICAL*(getPos().getY()-fluidSource.getY()); + float cost = ENERGY_COST_PUMP+ENERGY_COST_VERTICAL*(getBlockPos().getY()-fluidSource.getY()); // Found a fluid to suck-up! BlockState blockstate = w.getBlockState(fluidSource); Fluid f = getFluid(blockstate); if(f != null && getEnergy() >= cost){ this.getTank().fill(new FluidStack(f, FluidTank.BUCKET_VOLUME), true); this.subtractEnergy(cost, Power.ELECTRIC_POWER); - w.setBlockState(fluidSource, net.minecraft.block.Blocks.AIR.getDefaultState(), 3); + w.setBlock(fluidSource, net.minecraft.block.Blocks.AIR.defaultBlockState(), 3); success = true; } } timeUntilNextPump = PUMP_INTERVAL; } if(success){ - playSoundEffect(getPos().getX()+0.5, getPos().getY()+0.5, getPos().getZ()+0.5, SoundEvents.ITEM_BUCKET_FILL, 0.5f, 1f); - playSoundEffect(getPos().getX()+0.5, getPos().getY()+0.5, getPos().getZ()+0.5, SoundEvents.BLOCK_PISTON_EXTEND, 0.3f, 1f); + playSoundEffect(getBlockPos().getX()+0.5, getBlockPos().getY()+0.5, getBlockPos().getZ()+0.5, SoundEvents.BUCKET_FILL, 0.5f, 1f); + playSoundEffect(getBlockPos().getX()+0.5, getBlockPos().getY()+0.5, getBlockPos().getZ()+0.5, SoundEvents.PISTON_EXTEND, 0.3f, 1f); timeToSound = 14; } } } if(timeToSound == 1){ - playSoundEffect(getPos().getX()+0.5, getPos().getY()+0.5, getPos().getZ()+0.5, SoundEvents.BLOCK_PISTON_CONTRACT, 0.3f, 1f); + playSoundEffect(getBlockPos().getX()+0.5, getBlockPos().getY()+0.5, getBlockPos().getZ()+0.5, SoundEvents.PISTON_CONTRACT, 0.3f, 1f); } if(timeToSound > 0) timeToSound--; } @@ -130,7 +130,7 @@ protected boolean isValidInputItem(ItemStack item) { private Fluid getFluid(BlockState blockstate) { - return blockstate.getFluidState().isEmpty() ? null : blockstate.getFluidState().getFluid(); + return blockstate.getFluidState().isEmpty() ? null : blockstate.getFluidState().getType(); } @@ -145,7 +145,7 @@ private BlockPos scan(Set searchSpace, BlockPos coord, int limit) { BlockPos next; boolean nomore = true; for(Direction dir : Direction.values()){ - next = coord.offset(dir); + next = coord.relative(dir); if(!searchSpace.contains(next) && isFluidBlock(next)){ coord = next; nomore = false; @@ -161,14 +161,14 @@ private BlockPos scan(Set searchSpace, BlockPos coord, int limit) { } private boolean isSourceBlock( BlockPos coord){ - return getWorld().getFluidState(coord).isSource(); + return getLevel().getFluidState(coord).isSource(); } private boolean isFluidBlock(BlockPos coord) { - World w = getWorld(); - if(w.isBlockLoaded(coord) == false) return false; + World w = getLevel(); + if(w.hasChunkAt(coord) == false) return false; return !w.getFluidState(coord).isEmpty(); } @@ -183,7 +183,7 @@ public void powerUpdate(){ ConduitType type = Fluids.fluidToConduitType(getTank().getFluid().getFluid()); float availableAmount = getTank().getFluidAmount(); float delta = ConduitRegistry.transmitPowerToConsumers(availableAmount, zone.moddev.mc.poweradvantage.init.Fluids.fluidConduit_general, type, - PowerRequest.LAST_PRIORITY, getWorld(), getPos(), this); + PowerRequest.LAST_PRIORITY, getLevel(), getBlockPos(), this); if(delta > 0){ getTank().drain(Math.max((int)delta,1),true); // no free energy! } @@ -211,7 +211,7 @@ public void powerUpdate(){ } @Override protected boolean hasRedstoneSignal() { - return getWorld().isBlockPowered(getPos()); + return getLevel().hasNeighborSignal(getBlockPos()); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricStillBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricStillBlock.java index 4bed71a..1d86bcd 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricStillBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricStillBlock.java @@ -9,7 +9,7 @@ public class ElectricStillBlock extends ElectricMachineBlock{ @Override - public ElectricMachineTileEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public ElectricMachineTileEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new ElectricStillTileEntity(); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricStillTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricStillTileEntity.java index b983f43..9d19cf5 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricStillTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricStillTileEntity.java @@ -56,7 +56,7 @@ && canDistill(getInputTank().getFluid())){ } this.subtractEnergy(electricityPerDistill, Power.ELECTRIC_POWER); if(timeSinceSound > 200){ - playSoundEffect(getPos().getX()+0.5, getPos().getY()+0.5, getPos().getZ()+0.5, SoundEvents.BLOCK_LAVA_AMBIENT, 0.3f, 1.5f); + playSoundEffect(getBlockPos().getX()+0.5, getBlockPos().getY()+0.5, getBlockPos().getZ()+0.5, SoundEvents.LAVA_AMBIENT, 0.3f, 1.5f); timeSinceSound = 0; } timeSinceSound++; @@ -220,13 +220,13 @@ public void powerUpdate(){ ConduitType type = Fluids.fluidToConduitType(getOutputTank().getFluid().getFluid()); float availableAmount = getOutputTank().getFluidAmount(); float delta = ConduitRegistry.transmitPowerToConsumers(availableAmount, zone.moddev.mc.poweradvantage.init.Fluids.fluidConduit_general, type, - PowerRequest.LAST_PRIORITY, getWorld(), getPos(), this); + PowerRequest.LAST_PRIORITY, getLevel(), getBlockPos(), this); if(delta > 0){ getOutputTank().drain(Math.max((int)delta,1),true); // no free energy! } } - redstone = getWorld().isBlockPowered(getPos()); + redstone = getLevel().hasNeighborSignal(getBlockPos()); this.setPowerState(this.isPowered()); // automatically detect when a sync is needed diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberBlock.java index 45718a1..e48c174 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberBlock.java @@ -11,7 +11,7 @@ public GrowthChamberBlock(){ } @Override - public ElectricMachineTileEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public ElectricMachineTileEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new GrowthChamberTileEntity(); } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberControllerBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberControllerBlock.java index 144c3c2..a5a66d4 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberControllerBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberControllerBlock.java @@ -25,19 +25,19 @@ public GrowthChamberControllerBlock() { } @Override - public PoweredEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public PoweredEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new GrowthChamberControllerTileEntity(); } @Override - public boolean hasComparatorInputOverride(BlockState bs) { + public boolean hasAnalogOutputSignal(BlockState bs) { return true; } @Override - public int getComparatorInputOverride(BlockState bs, World world, BlockPos coord) { - if(world.getTileEntity(coord) instanceof GrowthChamberControllerTileEntity){ - return ((GrowthChamberControllerTileEntity)world.getTileEntity(coord)).getComparatorOutput(); + public int getAnalogOutputSignal(BlockState bs, World world, BlockPos coord) { + if(world.getBlockEntity(coord) instanceof GrowthChamberControllerTileEntity){ + return ((GrowthChamberControllerTileEntity)world.getBlockEntity(coord)).getComparatorOutput(); } return 0; } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberControllerTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberControllerTileEntity.java index 006b994..7822660 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberControllerTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberControllerTileEntity.java @@ -1,5 +1,7 @@ package zone.moddev.mc.electricadvantage.machines; +import net.minecraft.block.BlockState; + import zone.moddev.mc.electricadvantage.util.LegacyFluidHandler; import zone.moddev.mc.electricadvantage.init.Power; import cyano.poweradvantage.api.ConduitType; @@ -80,7 +82,7 @@ public void tickUpdate(boolean isServerWorld) { private static boolean isDirt(ItemStack i){ return i != null && !i.isEmpty() && (i.getItem() == net.minecraft.block.Blocks.DIRT.asItem() - || ItemTags.getCollection().getOrCreate(new ResourceLocation("forge", "dirt")).contains(i.getItem())); + || ItemTags.getAllTags().getTagOrEmpty(new ResourceLocation("forge", "dirt")).contains(i.getItem())); } private static float lowest(float... numbers){ @@ -92,7 +94,7 @@ private static float lowest(float... numbers){ } private boolean hasRedstoneSignal() { - return getWorld().isBlockPowered(getPos()); + return getLevel().hasNeighborSignal(getBlockPos()); } @@ -188,8 +190,8 @@ public void onDataFieldUpdate() { * @param tagRoot An NBT tag */ @Override - public CompoundNBT write(final CompoundNBT tagRoot) { - super.write(tagRoot); + public CompoundNBT save(final CompoundNBT tagRoot) { + super.save(tagRoot); CompoundNBT tankTag = new CompoundNBT(); this.getTank().writeToNBT(tankTag); tagRoot.put("Tank", tankTag); @@ -201,8 +203,8 @@ public CompoundNBT write(final CompoundNBT tagRoot) { * @param tagRoot An NBT tag */ @Override - public void read(final CompoundNBT tagRoot) { - super.read(tagRoot); + public void load(BlockState state, final CompoundNBT tagRoot) { + super.load(state, tagRoot); if (tagRoot.contains("Tank", 10)) { CompoundNBT tankTag = tagRoot.getCompound("Tank"); getTank().readFromNBT(tankTag); @@ -217,17 +219,17 @@ public void read(final CompoundNBT tagRoot) { } @Override - public boolean canInsertItem(final int slot, final ItemStack srcItem, final Direction side) { + public boolean canPlaceItemThroughFace(final int slot, final ItemStack srcItem, final Direction side) { return isDirt(srcItem) && slot == 0; } @Override - public boolean isItemValidForSlot(final int slot, final ItemStack srcItem) { + public boolean canPlaceItem(final int slot, final ItemStack srcItem) { return isDirt(srcItem) && slot == 0; } @Override - public boolean canExtractItem(final int slot, final ItemStack targetItem, final Direction side) { + public boolean canTakeItemThroughFace(final int slot, final ItemStack targetItem, final Direction side) { return false; } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberTileEntity.java index c990f71..507f4e4 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberTileEntity.java @@ -68,16 +68,16 @@ public void tickUpdate(boolean isServer) { List harvest = crops[slot].getHarvest(); if(harvest != null && (!harvest.isEmpty()) && this.hasSpaceForItemInOutputSlots(harvest.get(0))){ - playSoundEffect(getPos().getX()+0.5, getPos().getY()+0.5, getPos().getZ()+0.5, SoundEvents.BLOCK_GRASS_BREAK, 0.35f, 1f); + playSoundEffect(getBlockPos().getX()+0.5, getBlockPos().getY()+0.5, getBlockPos().getZ()+0.5, SoundEvents.GRASS_BREAK, 0.35f, 1f); for(ItemStack i : harvest){ ItemStack remainder = this.insertItemToOutputSlots(i); if(remainder != null){ - getWorld().addEntity( + getLevel().addFreshEntity( new ItemEntity( - getWorld(), - 2*(getWorld().rand.nextDouble()-0.5), - 2*(getWorld().rand.nextDouble()-0.5), - 2*(getWorld().rand.nextDouble()-0.5), + getLevel(), + 2*(getLevel().random.nextDouble()-0.5), + 2*(getLevel().random.nextDouble()-0.5), + 2*(getLevel().random.nextDouble()-0.5), remainder ) ); @@ -206,7 +206,7 @@ private void restorePendingCrops() { private VirtualCrop getVirtualCrop(ItemStack inputSlot) { if(isEmptyStack(inputSlot)) return null; try{ - return VirtualCrop.createVirtualCrop(inputSlot, getWorld(), getPos()); + return VirtualCrop.createVirtualCrop(inputSlot, getLevel(), getBlockPos()); } catch(Exception ex){ ElectricAdvantage.LOGGER.error("Error occurred while trying to make a virtual crop for {}", inputSlot, ex); return null; diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/HydroelectricGeneratorBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/HydroelectricGeneratorBlock.java index 063a872..cd7c312 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/HydroelectricGeneratorBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/HydroelectricGeneratorBlock.java @@ -11,14 +11,14 @@ public HydroelectricGeneratorBlock(){ } @Override - public ElectricGeneratorTileEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public ElectricGeneratorTileEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new HydroelectricGeneratorTileEntity(); } @Override - public boolean isValidPosition(BlockState state, IWorldReader worldIn, BlockPos pos) + public boolean canSurvive(BlockState state, IWorldReader worldIn, BlockPos pos) { - return super.isValidPosition(state, worldIn, pos) - && !worldIn.getBlockState(pos.down()).getMaterial().isSolid(); + return super.canSurvive(state, worldIn, pos) + && !worldIn.getBlockState(pos.below()).getMaterial().isSolid(); } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/HydroelectricGeneratorTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/HydroelectricGeneratorTileEntity.java index d8a8d91..051e1c4 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/HydroelectricGeneratorTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/HydroelectricGeneratorTileEntity.java @@ -30,11 +30,11 @@ public void tickUpdate(boolean isServer) { if(!isInitialized){ initialize(); } - if((getWorld().getGameTime() + checkOffset) % checkInterval == 0){ + if((getLevel().getGameTime() + checkOffset) % checkInterval == 0){ // periodically check if the hydroturbine entity is still present - List turbines = getWorld().getEntitiesWithinAABB(HydroturbineEntity.class, new AxisAlignedBB( - getPos().getX(),getPos().getY()-1,getPos().getZ(), - getPos().getX()+1,getPos().getY(),getPos().getZ()+1)); + List turbines = getLevel().getEntitiesOfClass(HydroturbineEntity.class, new AxisAlignedBB( + getBlockPos().getX(),getBlockPos().getY()-1,getBlockPos().getZ(), + getBlockPos().getX()+1,getBlockPos().getY(),getBlockPos().getZ()+1)); if(turbines == null || turbines.isEmpty()){ // turbine entity got deleted initialize(); @@ -45,8 +45,8 @@ public void tickUpdate(boolean isServer) { private void initialize() { isInitialized = true; - if(getPos().getY() > 0){ - getWorld().addEntity(new HydroturbineEntity(getWorld(),this)); + if(getBlockPos().getY() > 0){ + getLevel().addFreshEntity(new HydroturbineEntity(getLevel(),this)); } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/LEDBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/LEDBlock.java index 2103662..c3affba 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/LEDBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/LEDBlock.java @@ -16,34 +16,34 @@ public class LEDBlock extends ElectricConduitBlock implements ITileEntityProvide public LEDBlock() { super(); - setDefaultState(getStateContainer().getBaseState() - .with(WEST, false).with(DOWN, false).with(SOUTH, false) - .with(EAST, false).with(UP, false).with(NORTH, false) - .with(LIT, false)); + registerDefaultState(getStateDefinition().any() + .setValue(WEST, false).setValue(DOWN, false).setValue(SOUTH, false) + .setValue(EAST, false).setValue(UP, false).setValue(NORTH, false) + .setValue(LIT, false)); } @Override - public TileEntity createNewTileEntity(IBlockReader world) { + public TileEntity newBlockEntity(IBlockReader world) { return new LEDTileEntity(); } @Override - public int getLightValue(BlockState state) { - return state.getBlock() == this && state.get(LIT) ? 15 : 0; + public int getLightValue(BlockState state, IBlockReader world, net.minecraft.util.math.BlockPos pos) { + return state.getBlock() == this && state.getValue(LIT) ? 15 : 0; } @Override - protected void fillStateContainer(StateContainer.Builder builder) { - super.fillStateContainer(builder); + protected void createBlockStateDefinition(StateContainer.Builder builder) { + super.createBlockStateDefinition(builder); builder.add(LIT); } public BlockState getStateFromLegacyMeta(int meta) { - return getDefaultState().with(LIT, (meta & 1) != 0); + return defaultBlockState().setValue(LIT, (meta & 1) != 0); } public int getLegacyMetaFromState(BlockState state) { - return state.get(LIT) ? 1 : 0; + return state.getValue(LIT) ? 1 : 0; } @Override diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/LEDTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/LEDTileEntity.java index ba6dfef..3d7b669 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/LEDTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/LEDTileEntity.java @@ -50,12 +50,12 @@ public void tickUpdate(boolean arg0) { public void powerUpdate(){ super.powerUpdate(); boolean on = getEnergy(Power.ELECTRIC_POWER) > 0; - BlockState bs = getWorld().getBlockState(getPos()); + BlockState bs = getLevel().getBlockState(getBlockPos()); if(on){ this.subtractEnergy(ENERGY_COST, Power.ELECTRIC_POWER); } - if((Boolean)bs.get(LEDBlock.LIT) != on){ - getWorld().setBlockState(getPos(),bs.with(LEDBlock.LIT, on)); + if((Boolean)bs.getValue(LEDBlock.LIT) != on){ + getLevel().setBlockAndUpdate(getBlockPos(),bs.setValue(LEDBlock.LIT, on)); } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/LaserTurretBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/LaserTurretBlock.java index 2dbd918..b9bd5ed 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/LaserTurretBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/LaserTurretBlock.java @@ -18,19 +18,19 @@ public class LaserTurretBlock extends ElectricMachineBlock { private static final VoxelShape SHAPE = VoxelShapes.or( - Block.makeCuboidShape(0, 0, 0, 16, 4, 16), - Block.makeCuboidShape(4, 4, 4, 12, 16, 12)); + Block.box(0, 0, 0, 16, 4, 16), + Block.box(4, 4, 4, 12, 16, 12)); // Evil laser turrets target players and not hostile mobs public final boolean evil; public LaserTurretBlock(boolean isEvil) { - super(Block.Properties.create(Material.PISTON) - .hardnessAndResistance(5.0F, 100.0F).variableOpacity().notSolid()); + super(Block.Properties.of(Material.PISTON) + .strength(5.0F, 100.0F).dynamicShape().noOcclusion()); this.evil = isEvil; } @Override - public ElectricMachineTileEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public ElectricMachineTileEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new LaserTurretTileEntity(); } @@ -48,9 +48,9 @@ public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockP } @Override - public void onBlockPlacedBy(World w, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) { - super.onBlockPlacedBy(w, pos, state, placer, stack); - TileEntity te = w.getTileEntity(pos); + public void setPlacedBy(World w, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) { + super.setPlacedBy(w, pos, state, placer, stack); + TileEntity te = w.getBlockEntity(pos); if(placer instanceof PlayerEntity && te instanceof LaserTurretTileEntity){ ((LaserTurretTileEntity)te).setOwner((PlayerEntity)placer); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/LaserTurretTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/LaserTurretTileEntity.java index 1fd55d8..4a6c19f 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/LaserTurretTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/LaserTurretTileEntity.java @@ -3,6 +3,7 @@ import zone.moddev.mc.electricadvantage.ElectricAdvantage; import zone.moddev.mc.electricadvantage.init.Power; import net.minecraft.block.Block; +import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.EntityClassification; @@ -18,6 +19,7 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.*; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -70,7 +72,7 @@ public class LaserTurretTileEntity extends ElectricMachineTileEntity implements /** used by renderer to draw laser line */ public double laserBlastLength = 0; - private Vec3d opticPosition = null; + private Vector3d opticPosition = null; /** rotation speed (non-idle), in degrees per tick */ public final float speed = 9f; @@ -80,7 +82,7 @@ public LaserTurretTileEntity(){ super(zone.moddev.mc.electricadvantage.init.Entities.LASER_TURRET, "tile.electricadvantage.laser_turret.name",MAX_BUFFER,0,0,0); SoundEvent soundEvent = ForgeRegistries.SOUND_EVENTS.getValue(new ResourceLocation(ElectricAdvantage.INSTANCE.LASER_SOUND)); if(soundEvent == null){ - LASER_SOUND = SoundEvents.ENTITY_ENDERMAN_TELEPORT; + LASER_SOUND = SoundEvents.ENDERMAN_TELEPORT; } else { LASER_SOUND = soundEvent; } @@ -93,12 +95,12 @@ public boolean isActive(){ @Override public void tickUpdate(boolean b) { - World w = getWorld(); + World w = getLevel(); if(laserAttack > 0){ laserAttack--; } boolean isActive = isActive(); - if(w.isRemote){ + if(w.isClientSide){ // client-side only if(isActive){ if(targetLocked == false){ @@ -111,7 +113,7 @@ public void tickUpdate(boolean b) { } } else { storeOld(); - Entity e = w.getEntityByID(targetID); + Entity e = w.getEntity(targetID); if(e != null){ lookAt(e); } @@ -141,7 +143,7 @@ public void tickUpdate(boolean b) { // Server side only if(isActive){ if(targetLocked == false){ - final Block thisBlock = getWorld().getBlockState(getPos()).getBlock(); + final Block thisBlock = getLevel().getBlockState(getBlockPos()).getBlock(); final boolean isEvil; if(thisBlock instanceof LaserTurretBlock && ((LaserTurretBlock)thisBlock).evil){ @@ -152,13 +154,13 @@ public void tickUpdate(boolean b) { double x = this.getOpticPosition().x; double y = this.getOpticPosition().y; double z = this.getOpticPosition().z; - List entities = w.getEntitiesWithinAABB(LivingEntity.class, new AxisAlignedBB(x-TARGET_RANGE, y-TARGET_RANGE, z-TARGET_RANGE, x+TARGET_RANGE, y+TARGET_RANGE, z+TARGET_RANGE)); + List entities = w.getEntitiesOfClass(LivingEntity.class, new AxisAlignedBB(x-TARGET_RANGE, y-TARGET_RANGE, z-TARGET_RANGE, x+TARGET_RANGE, y+TARGET_RANGE, z+TARGET_RANGE)); final double maxRangeSquared = TARGET_RANGE * TARGET_RANGE; if(isEvil){ for (Entity e : entities) { if (!( - e.getType().getClassification() == EntityClassification.MONSTER - || e.getType().getClassification() == EntityClassification.AMBIENT + e.getType().getCategory() == EntityClassification.MONSTER + || e.getType().getCategory() == EntityClassification.AMBIENT ) ) { if (canSeeEntity(e)) { @@ -169,14 +171,14 @@ public void tickUpdate(boolean b) { } } else { for (Entity e : entities) { - if (e.getPositionVector().squareDistanceTo(getOpticPosition()) > maxRangeSquared) continue; + if (e.position().distanceToSqr(getOpticPosition()) > maxRangeSquared) continue; if (e instanceof PlayerEntity) { if (isEnemy((PlayerEntity) e)) { setTarget(e); break; } } - if (e.getType().getClassification() == EntityClassification.MONSTER) { + if (e.getType().getCategory() == EntityClassification.MONSTER) { if (canSeeEntity(e)) { setTarget(e); break; @@ -193,7 +195,7 @@ public void tickUpdate(boolean b) { playSoundEffect(getOpticPosition().x, getOpticPosition().y, getOpticPosition().z, LASER_SOUND,1F,1F); List victims = getLaserAttackVictims(); - Entity e = w.getEntityByID(targetID); + Entity e = w.getEntity(targetID); for(Entity v : victims){ hurtVictim(v); } @@ -235,24 +237,24 @@ public boolean showLaserLine(){ private List getLaserAttackVictims(){ - final Vec3d origin = getOpticPosition(); - final Vec3d dir; - final World w = getWorld(); - final Entity e = w.getEntityByID(targetID); + final Vector3d origin = getOpticPosition(); + final Vector3d dir; + final World w = getLevel(); + final Entity e = w.getEntity(targetID); if(e != null){ - dir = e.getPositionVector().add(0, 0.5*e.getHeight(), 0).subtract(origin).normalize(); + dir = e.position().add(0, 0.5*e.getBbHeight(), 0).subtract(origin).normalize(); } else { - dir = (new Vec3d(Math.cos(DEGREES_TO_RADIANS * rotYaw),Math.sin(rotPitch),Math.sin(rotYaw))).normalize(); + dir = (new Vector3d(Math.cos(DEGREES_TO_RADIANS * rotYaw),Math.sin(rotPitch),Math.sin(rotYaw))).normalize(); } - final Vec3d terminus = followRayToSolidBlock(origin,dir,ATTACK_RANGE); - final double maxDistSqr = origin.squareDistanceTo(terminus); + final Vector3d terminus = followRayToSolidBlock(origin,dir,ATTACK_RANGE); + final double maxDistSqr = origin.distanceToSqr(terminus); final double maxDist = Math.sqrt(maxDistSqr); - List potentialVictims = w.getEntitiesWithinAABB(LivingEntity.class, new AxisAlignedBB( + List potentialVictims = w.getEntitiesOfClass(LivingEntity.class, new AxisAlignedBB( origin.x - maxDist, origin.y - maxDist, origin.z - maxDist, origin.x + maxDist, origin.y + maxDist, origin.z + maxDist)); List victims = new ArrayList<>(); for(Entity v : potentialVictims){ - if(origin.squareDistanceTo(v.getPositionVector()) < maxDistSqr + if(origin.distanceToSqr(v.position()) < maxDistSqr && rayIntersectsBoundingBox(origin,dir,v.getBoundingBox())){ victims.add(v); } @@ -263,17 +265,17 @@ && rayIntersectsBoundingBox(origin,dir,v.getBoundingBox())){ private void hurtVictim(Entity e){ - e.setFire(BURN_TIME); + e.setSecondsOnFire(BURN_TIME); if(e instanceof LivingEntity){ - ((LivingEntity)e).attackEntityFrom(Power.laser_damage, ATTACK_DAMAGE); - BlockPos bp = e.getPosition(); - if(getWorld().isAirBlock(bp) && !getWorld().isAirBlock(bp.down())){ - getWorld().setBlockState(bp, Blocks.FIRE.getDefaultState()); + ((LivingEntity)e).hurt(Power.laser_damage, ATTACK_DAMAGE); + BlockPos bp = e.blockPosition(); + if(getLevel().isEmptyBlock(bp) && !getLevel().isEmptyBlock(bp.below())){ + getLevel().setBlockAndUpdate(bp, Blocks.FIRE.defaultBlockState()); } if(playerOwner != null && !playerOwner.isEmpty()){ - for (PlayerEntity player : getWorld().getPlayers()) { + for (PlayerEntity player : getLevel().players()) { if (playerOwner.equals(player.getName().getString())) { - ((LivingEntity) e).setRevengeTarget(player); + ((LivingEntity) e).setLastHurtByMob(player); break; } } @@ -281,34 +283,34 @@ private void hurtVictim(Entity e){ } } - private Vec3d calculateLaserTerminus(){ - Vec3d dir; - World w = getWorld(); - Entity e = w.getEntityByID(targetID); + private Vector3d calculateLaserTerminus(){ + Vector3d dir; + World w = getLevel(); + Entity e = w.getEntity(targetID); if(e != null){ - dir = e.getPositionVector().add(0, 0.5*e.getHeight(), 0).subtract(this.getOpticPosition()).normalize(); + dir = e.position().add(0, 0.5*e.getBbHeight(), 0).subtract(this.getOpticPosition()).normalize(); } else { - dir = (new Vec3d(Math.cos(DEGREES_TO_RADIANS * rotYaw),Math.sin(rotPitch),Math.sin(rotYaw))).normalize(); + dir = (new Vector3d(Math.cos(DEGREES_TO_RADIANS * rotYaw),Math.sin(rotPitch),Math.sin(rotYaw))).normalize(); } return followRayToSolidBlock(getOpticPosition(),dir,ATTACK_RANGE); } - private Vec3d followRayToSolidBlock(Vec3d origin, Vec3d dir, double maxRange){ - Vec3d max = origin.add(dir).add(maxRange * dir.x, maxRange * dir.y, maxRange * dir.z); - BlockRayTraceResult impact = getWorld().rayTraceBlocks(new RayTraceContext(origin, max, + private Vector3d followRayToSolidBlock(Vector3d origin, Vector3d dir, double maxRange){ + Vector3d max = origin.add(dir).add(maxRange * dir.x, maxRange * dir.y, maxRange * dir.z); + BlockRayTraceResult impact = getLevel().clip(new RayTraceContext(origin, max, RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.SOURCE_ONLY, null)); if(impact.getType() == RayTraceResult.Type.BLOCK){ - return impact.getHitVec(); + return impact.getLocation(); } else { return max; } } - public static boolean rayIntersectsBoundingBox(Vec3d rayOrigin, Vec3d rayDirection, AxisAlignedBB box){ + public static boolean rayIntersectsBoundingBox(Vector3d rayOrigin, Vector3d rayDirection, AxisAlignedBB box){ if(box == null) { return false; } // algorithm from http://gamedev.stackexchange.com/questions/18436/most-efficient-aabb-vs-ray-collision-algorithms - Vec3d inverse = new Vec3d(1.0 / rayDirection.x, 1.0 / rayDirection.y, 1.0 / rayDirection.z); + Vector3d inverse = new Vector3d(1.0 / rayDirection.x, 1.0 / rayDirection.y, 1.0 / rayDirection.z); double t1 = (box.minX - rayOrigin.x)*inverse.x; double t2 = (box.maxX- rayOrigin.x)*inverse.x; double t3 = (box.minY - rayOrigin.y)*inverse.y; @@ -335,8 +337,8 @@ public static boolean rayIntersectsBoundingBox(Vec3d rayOrigin, Vec3d rayDirecti } - private static Vec3d mul(Vec3d a, double b){ - return new Vec3d(a.x * b, a.y * b, a.z * b); + private static Vector3d mul(Vector3d a, double b){ + return new Vector3d(a.x * b, a.y * b, a.z * b); } private static double max(double a, double b){ return Math.max(a, b); @@ -348,21 +350,21 @@ private static double min(double a, double b){ private void drawLaserLine() { // client-side only - World w = getWorld(); - if(w.isRemote){ + World w = getLevel(); + if(w.isClientSide){ this.laserBlastLength = getOpticPosition().distanceTo(calculateLaserTerminus()); } } private void validateTarget() { if(targetLocked){ - Entity e = getWorld().getEntityByID(targetID); + Entity e = getLevel().getEntity(targetID); if(e == null || !e.isAlive()){ setTarget(null); return; } - if(getOpticPosition().distanceTo(e.getPositionVector()) > TARGET_RANGE){ + if(getOpticPosition().distanceTo(e.position()) > TARGET_RANGE){ setTarget(null); return; } @@ -376,9 +378,9 @@ private void validateTarget() { public boolean canSeeEntity(Entity e){ if(e == null) return false; - Vec3d offsetOrigin = getOpticPosition().add(e.getPositionVector().subtract(getOpticPosition()).normalize()); - BlockRayTraceResult collision = getWorld().rayTraceBlocks(new RayTraceContext(offsetOrigin, - e.getPositionVector().add(0, e.getHeight()*0.5, 0), RayTraceContext.BlockMode.COLLIDER, + Vector3d offsetOrigin = getOpticPosition().add(e.position().subtract(getOpticPosition()).normalize()); + BlockRayTraceResult collision = getLevel().clip(new RayTraceContext(offsetOrigin, + e.position().add(0, e.getBbHeight()*0.5, 0), RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.SOURCE_ONLY, null)); if(collision.getType() == RayTraceResult.Type.BLOCK){ return false; @@ -392,7 +394,7 @@ public void setTarget(Entity e){ this.targetLocked = false; laserAttack = 0; } else { - this.targetID = e.getEntityId(); + this.targetID = e.getId(); this.targetLocked = true; laserAttack = LASER_CHARGEUP_TIME; lookAt(e); @@ -401,11 +403,11 @@ public void setTarget(Entity e){ } private void lookAt(Entity e) { - Vec3d pos = e.getPositionVector().add(0, e.getHeight()*0.5, 0); + Vector3d pos = e.position().add(0, e.getBbHeight()*0.5, 0); targetPosition(pos); } - private Vec3d getOpticPosition(){ + private Vector3d getOpticPosition(){ if(opticPosition == null)setOpticPosition(); return opticPosition; } @@ -424,17 +426,17 @@ public void setTeam(Team t){ } @Override - public void setPos(BlockPos p){ - super.setPos(p); + public void setPosition(BlockPos p){ + super.setPosition(p); setOpticPosition(); } public final void setOpticPosition(){ - BlockPos p = getPos(); - opticPosition = new Vec3d(p.getX()+0.5,p.getY()+0.75,p.getZ()+0.5); + BlockPos p = getBlockPos(); + opticPosition = new Vector3d(p.getX()+0.5,p.getY()+0.75,p.getZ()+0.5); } - private void targetPosition(Vec3d coord) { - Vec3d pos = getOpticPosition(); + private void targetPosition(Vector3d coord) { + Vector3d pos = getOpticPosition(); double x = pos.x; double y = pos.y; double z = pos.z; @@ -488,19 +490,19 @@ private void storeOld(){ public SUpdateTileEntityPacket getUpdatePacket(){ CompoundNBT nbtTag = new CompoundNBT(); writeRenderSync(nbtTag); - return new SUpdateTileEntityPacket(this.getPos(), 0, nbtTag); + return new SUpdateTileEntityPacket(this.getBlockPos(), 0, nbtTag); } @Override public CompoundNBT getUpdateTag() { - CompoundNBT nbtTag = write(new CompoundNBT()); + CompoundNBT nbtTag = save(new CompoundNBT()); writeRenderSync(nbtTag); return nbtTag; } @Override - public void handleUpdateTag(CompoundNBT tag) { - read(tag); + public void handleUpdateTag(BlockState state, CompoundNBT tag) { + load(state, tag); readRenderSync(tag); } @@ -508,9 +510,9 @@ private void writeRenderSync(CompoundNBT nbtTag) { nbtTag.putFloat("energy", getEnergy()); nbtTag.putBoolean("lock", targetLocked); if(targetLocked){ - if(targetID != Integer.MIN_VALUE && getWorld().getEntityByID(targetID) != null){ - Entity e = getWorld().getEntityByID(targetID); - Vec3d pos = e.getPositionVector().add(0, e.getHeight()*0.5, 0); + if(targetID != Integer.MIN_VALUE && getLevel().getEntity(targetID) != null){ + Entity e = getLevel().getEntity(targetID); + Vector3d pos = e.position().add(0, e.getBbHeight()*0.5, 0); CompoundNBT target = new CompoundNBT(); target.putInt("id", this.targetID); target.putFloat("yaw", rotTargetYaw); @@ -526,7 +528,7 @@ private void writeRenderSync(CompoundNBT nbtTag) { */ @Override public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket packet) { - readRenderSync(packet.getNbtCompound()); + readRenderSync(packet.getTag()); } private void readRenderSync(CompoundNBT tag) { @@ -535,7 +537,7 @@ private void readRenderSync(CompoundNBT tag) { if(tag.contains("target", 10)){ CompoundNBT target = tag.getCompound("target"); this.targetID = target.getInt("id"); - Entity e = getWorld().getEntityByID(targetID); + Entity e = getLevel().getEntity(targetID); if(e != null){ this.lookAt(e); } else { @@ -642,6 +644,6 @@ public int getComparatorOutput(){ @OnlyIn(Dist.CLIENT) public AxisAlignedBB getRenderBoundingBox() { - return new AxisAlignedBB(getPos().add(-renderRange, -renderRange, -renderRange), getPos().add(renderRange, renderRange, renderRange)); + return new AxisAlignedBB(getBlockPos().offset(-renderRange, -renderRange, -renderRange), getBlockPos().offset(renderRange, renderRange, renderRange)); } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/PhotovoltaicGeneratorBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/PhotovoltaicGeneratorBlock.java index 5a13ffd..f656ae5 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/PhotovoltaicGeneratorBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/PhotovoltaicGeneratorBlock.java @@ -8,22 +8,16 @@ public class PhotovoltaicGeneratorBlock extends ElectricGeneratorBlock{ public PhotovoltaicGeneratorBlock(){ - super(net.minecraft.block.Block.Properties.create(Material.ROCK) - .hardnessAndResistance(0.75F).sound(SoundType.GLASS).variableOpacity()); + super(net.minecraft.block.Block.Properties.of(Material.STONE) + .strength(0.75F).sound(SoundType.GLASS).dynamicShape() + .isRedstoneConductor((state, world, pos) -> true)); } @Override - public ElectricGeneratorTileEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public ElectricGeneratorTileEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new PhotovoltaicGeneratorTileEntity(); } - @Override - public boolean isNormalCube(BlockState bs, net.minecraft.world.IBlockReader world, net.minecraft.util.math.BlockPos pos) - { - return true; - } - - } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/PhotovoltaicGeneratorTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/PhotovoltaicGeneratorTileEntity.java index b073198..c9125ea 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/PhotovoltaicGeneratorTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/PhotovoltaicGeneratorTileEntity.java @@ -76,7 +76,7 @@ public void tickUpdate(boolean isServer) { public void powerUpdate(){ float power; if(hasRedstoneSignal() == false){ - float solar = getLightIntensityAt(getPos(),getWorld()); + float solar = getLightIntensityAt(getBlockPos(),getLevel()); power = Math.max(0,MAX_SOLAR_OUTPUT * solar); this.addEnergy(power, Power.ELECTRIC_POWER); } else { @@ -93,7 +93,7 @@ public void powerUpdate(){ public static float getLightIntensityAt(BlockPos pos, World w){ float light; - if(w.canSeeSky(pos) && w.dimension.hasSkyLight()){ + if(w.canSeeSky(pos) && w.dimensionType().hasSkyLight()){ // outdoor light imposes no penalty light = MathHelper.sin((float)w.getDayTime() * 2.61799E-4f); // (worldTime * pi / 12000); // handle weather @@ -103,7 +103,7 @@ public static float getLightIntensityAt(BlockPos pos, World w){ light *= 0.35f; } } else { - float blockLight = w.getLight(pos) * 6.66666E-2f; // block light / 15 + float blockLight = w.getMaxLocalRawBrightness(pos) * 6.66666E-2f; // block light / 15 light = BLOCKLIGHT_FACTOR * blockLight; } return light; diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/PlasticRefineryBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/PlasticRefineryBlock.java index 1796f11..b6f6db2 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/PlasticRefineryBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/PlasticRefineryBlock.java @@ -8,7 +8,7 @@ public class PlasticRefineryBlock extends ElectricMachineBlock{ @Override - public ElectricMachineTileEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public ElectricMachineTileEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new PlasticRefineryTileEntity(); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/PlasticRefineryTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/PlasticRefineryTileEntity.java index 3a1f18c..89ade28 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/PlasticRefineryTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/PlasticRefineryTileEntity.java @@ -63,7 +63,7 @@ && getTank().getFluidAmount() >= OIL_PER_INGOT){ // done getTank().drain(OIL_PER_INGOT, true); this.insertItemToOutputSlots(new ItemStack(Items.petrolplastic_ingot,1)); - playSoundEffect(getPos().getX()+0.5, getPos().getY()+0.5, getPos().getZ()+0.5, SoundEvents.BLOCK_ANVIL_LAND, 0.15f, 1f); + playSoundEffect(getBlockPos().getX()+0.5, getBlockPos().getY()+0.5, getBlockPos().getZ()+0.5, SoundEvents.ANVIL_LAND, 0.15f, 1f); fabTime = 0; if(wasActive){ this.setActiveState(false); @@ -128,7 +128,7 @@ protected void loadFrom(CompoundNBT tagRoot) { @Override protected boolean isValidInputItem(ItemStack item) { return item != null && !item.isEmpty() - && ItemTags.getCollection().getOrCreate(new ResourceLocation("forge", "plastics")) + && ItemTags.getAllTags().getTagOrEmpty(new ResourceLocation("forge", "plastics")) .contains(item.getItem()); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/SteamPoweredElectricGeneratorBlock.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/SteamPoweredElectricGeneratorBlock.java index ab7698c..1f13abd 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/SteamPoweredElectricGeneratorBlock.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/SteamPoweredElectricGeneratorBlock.java @@ -9,7 +9,7 @@ public class SteamPoweredElectricGeneratorBlock extends ElectricGeneratorBlock{ public static final ConduitType STEAM_POWER = new ConduitType("steam"); @Override - public ElectricGeneratorTileEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public ElectricGeneratorTileEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new SteamPoweredElectricGeneratorTileEntity(); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/SteamPoweredElectricGeneratorTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/SteamPoweredElectricGeneratorTileEntity.java index a4133d9..0034d26 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/SteamPoweredElectricGeneratorTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/SteamPoweredElectricGeneratorTileEntity.java @@ -46,8 +46,8 @@ public SteamPoweredElectricGeneratorTileEntity() { } super.powerUpdate(); super.setActive(flag); - if(flag && getWorld().rand.nextInt(200) == 0){ - playSoundEffect(getPos().getX()+0.5, getPos().getY()+0.5, getPos().getZ()+0.5, SoundEvents.BLOCK_FIRE_EXTINGUISH, 0.25f, 1f); + if(flag && getLevel().random.nextInt(200) == 0){ + playSoundEffect(getBlockPos().getX()+0.5, getBlockPos().getY()+0.5, getBlockPos().getZ()+0.5, SoundEvents.FIRE_EXTINGUISH, 0.25f, 1f); } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/migration/ElectricLegacyMigrations.java b/src/main/java/zone/moddev/mc/electricadvantage/migration/ElectricLegacyMigrations.java index 13aedea..741e6f7 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/migration/ElectricLegacyMigrations.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/migration/ElectricLegacyMigrations.java @@ -67,9 +67,9 @@ private static void registerTile(String path) { private static BlockState decodeState(Block block, int metadata) { if (block instanceof ElectricDrillBlock) { - return block.getDefaultState() - .with(ElectricDrillBlock.FACING, legacyDrillFacing(metadata)) - .with(ElectricDrillBlock.ACTIVE, legacyDrillActive(metadata)); + return block.defaultBlockState() + .setValue(ElectricDrillBlock.FACING, legacyDrillFacing(metadata)) + .setValue(ElectricDrillBlock.ACTIVE, legacyDrillActive(metadata)); } if (block instanceof LEDBlock) { return ((LEDBlock) block).getStateFromLegacyMeta(metadata); @@ -86,11 +86,11 @@ private static BlockState decodeState(Block block, int metadata) { if (block instanceof BlockSimplePowerMachine) { return ((BlockSimplePowerMachine) block).getStateFromMeta(metadata); } - return block.getDefaultState(); + return block.defaultBlockState(); } static Direction legacyDrillFacing(int metadata) { - return Direction.byIndex(metadata & 0x7); + return Direction.from3DDataValue(metadata & 0x7); } static boolean legacyDrillActive(int metadata) { diff --git a/src/main/java/zone/moddev/mc/electricadvantage/recipe/RecipeConditions.java b/src/main/java/zone/moddev/mc/electricadvantage/recipe/RecipeConditions.java index c0ed0ad..62a6f00 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/recipe/RecipeConditions.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/recipe/RecipeConditions.java @@ -55,7 +55,7 @@ static final class ModeSerializer implements IConditionSerializer @Override public ModeCondition read(JsonObject json) { return new ModeCondition(RecipeMode.valueOf( - JSONUtils.getString(json, "mode").toUpperCase(Locale.ROOT)), inverted); + JSONUtils.getAsString(json, "mode").toUpperCase(Locale.ROOT)), inverted); } @Override public ResourceLocation getID() { diff --git a/src/main/java/zone/moddev/mc/electricadvantage/util/crafting/ItemMatcher.java b/src/main/java/zone/moddev/mc/electricadvantage/util/crafting/ItemMatcher.java index cef8e4d..f9d3354 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/util/crafting/ItemMatcher.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/util/crafting/ItemMatcher.java @@ -18,7 +18,7 @@ public final class ItemMatcher { public ItemMatcher(String legacyName) { this.choices = new ArrayList<>(); - for (Item item : ItemTags.getCollection().getOrCreate(tagId(legacyName)).getAllElements()) { + for (Item item : ItemTags.getAllTags().getTagOrEmpty(tagId(legacyName)).getValues()) { choices.add(new ItemStack(item)); } } @@ -52,7 +52,7 @@ public boolean matches(ItemRecord record) { public boolean matches(ItemStack candidate) { if (candidate == null || candidate.isEmpty()) return false; for (ItemStack choice : choices) { - if (ItemStack.areItemsEqual(choice, candidate)) return true; + if (ItemStack.isSame(choice, candidate)) return true; } return false; } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/util/crafting/ItemRecord.java b/src/main/java/zone/moddev/mc/electricadvantage/util/crafting/ItemRecord.java index 3fa271e..b8ec807 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/util/crafting/ItemRecord.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/util/crafting/ItemRecord.java @@ -22,6 +22,6 @@ public ItemStack getItem() { @Override public boolean equals(Object other) { return other == this || other instanceof ItemRecord - && ItemStack.areItemsEqual(item, ((ItemRecord) other).item); + && ItemStack.isSame(item, ((ItemRecord) other).item); } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/util/crafting/RecipeDeconstructor.java b/src/main/java/zone/moddev/mc/electricadvantage/util/crafting/RecipeDeconstructor.java index ef3dcb7..126cd80 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/util/crafting/RecipeDeconstructor.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/util/crafting/RecipeDeconstructor.java @@ -38,7 +38,7 @@ private void initializeRecipeCache(World world) { if (cachedRecipeCount == recipes.size() && !recipeCache.isEmpty()) return; recipeCache.clear(); for (IRecipe recipe : recipes) { - ItemStack output = recipe.getRecipeOutput(); + ItemStack output = recipe.getResultItem(); if (output == null || output.isEmpty()) continue; recipeCache.computeIfAbsent(new ItemRecord(output), ignored -> new ArrayList<>()).add(recipe); } @@ -62,7 +62,7 @@ private SerializedInventory attemptToCraft(World world, ItemStack target, boolean failed = false; for (Ingredient ingredient : recipe.getIngredients()) { if (ingredient == null || ingredient == Ingredient.EMPTY) continue; - ItemStack[] matching = ingredient.getMatchingStacks(); + ItemStack[] matching = ingredient.getItems(); if (matching == null || matching.length == 0) { failed = true; break; @@ -93,7 +93,7 @@ private SerializedInventory attemptToCraft(World world, ItemStack target, } } if (!failed) { - output.set(recipe.getRecipeOutput().copy()); + output.set(recipe.getResultItem().copy()); return candidate; } } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/util/farming/VirtualCrop.java b/src/main/java/zone/moddev/mc/electricadvantage/util/farming/VirtualCrop.java index 31f1301..648d41e 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/util/farming/VirtualCrop.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/util/farming/VirtualCrop.java @@ -3,7 +3,7 @@ import zone.moddev.mc.electricadvantage.util.crafting.ItemRecord; import net.minecraft.block.Block; import net.minecraft.block.StemBlock; -import net.minecraft.state.IProperty; +import net.minecraft.state.Property; import net.minecraft.state.IntegerProperty; import net.minecraft.block.BlockState; import net.minecraft.item.Items; @@ -64,7 +64,7 @@ public static VirtualCrop createVirtualCrop(ItemStack stack, World w, BlockPos p Block block = startingState.getBlock(); int numStages = getNumberOfGrowthStages(startingState); if(block instanceof StemBlock){ - Block product = ((StemBlock)block).getCrop(); + Block product = ((StemBlock)block).getFruit(); if(product == null) { return null; } @@ -86,11 +86,11 @@ public VirtualCrop copy(){ private static int getNumberOfGrowthStages(BlockState startingState) { - for(IProperty property : startingState.getProperties()){ + for(Property property : startingState.getProperties()){ if(property instanceof IntegerProperty){ IntegerProperty prop = (IntegerProperty)property; if("age".equals(prop.getName())){ - return prop.getAllowedValues().size(); + return prop.getPossibleValues().size(); } } } @@ -99,15 +99,15 @@ private static int getNumberOfGrowthStages(BlockState startingState) { private static BlockState ageToMax(BlockState startingState) { - for(IProperty property : startingState.getProperties()){ + for(Property property : startingState.getProperties()){ if(property instanceof IntegerProperty){ IntegerProperty prop = (IntegerProperty)property; if("age".equals(prop.getName())){ int max = 0; - for(Object i : prop.getAllowedValues()){ + for(Object i : prop.getPossibleValues()){ if((Integer)i > max){max = (Integer)i;} } - return startingState.with(prop, Integer.valueOf(max)); + return startingState.setValue(prop, Integer.valueOf(max)); } } } diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 863503a..719d542 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -30,13 +30,13 @@ side="BOTH" [[dependencies.electricadvantage]] modId="poweradvantage" mandatory=true -versionRange="[2.4.6.115021,3.0.0)" +versionRange="[2.4.7.116051,3.0.0)" ordering="AFTER" side="BOTH" [[dependencies.electricadvantage]] modId="basemetals" mandatory=false -versionRange="[3.0.1.115021,4.0.0)" +versionRange="[3.1.1.116051,4.0.0)" ordering="AFTER" side="BOTH" diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index e779902..636d0bd 100644 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -1,6 +1,6 @@ { "pack":{ - "pack_format":5, + "pack_format":6, "description":"Electric Advantage" } } diff --git a/src/test/java/zone/moddev/mc/electricadvantage/blocks/NativeBlockContractTest.java b/src/test/java/zone/moddev/mc/electricadvantage/blocks/NativeBlockContractTest.java index 9167151..a5bb02d 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/blocks/NativeBlockContractTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/blocks/NativeBlockContractTest.java @@ -23,15 +23,17 @@ import static org.junit.Assert.*; public class NativeBlockContractTest { - @BeforeClass public static void bootstrapNativeRegistries() { Bootstrap.register(); } + @BeforeClass public static void bootstrapNativeRegistries() { Bootstrap.bootStrap(); } @Test public void scaffoldRetainsNonSolidFullCollisionAndSharedStateProperties() { ElectricScaffoldBlock block = new ElectricScaffoldBlock(); - BlockState state = block.getDefaultState(); - assertFalse(state.isSolid()); - assertFalse(block.isNormalCube(state, null, BlockPos.ZERO)); - assertEquals(VoxelShapes.fullCube().getBoundingBox(), - block.getCollisionShape(state, null, BlockPos.ZERO, ISelectionContext.dummy()).getBoundingBox()); + BlockState state = block.defaultBlockState(); + assertFalse(state.canOcclude()); + assertFalse(state.isRedstoneConductor(net.minecraft.world.EmptyBlockReader.INSTANCE, BlockPos.ZERO)); + assertEquals(VoxelShapes.block().bounds(), + block.getCollisionShape(state, null, BlockPos.ZERO, ISelectionContext.empty()).bounds()); + assertFalse(state.isSolidRender(net.minecraft.world.EmptyBlockReader.INSTANCE, BlockPos.ZERO)); + assertTrue(state.isCollisionShapeFullBlock(net.minecraft.world.EmptyBlockReader.INSTANCE, BlockPos.ZERO)); assertEquals(6, state.getProperties().size()); assertSame(BlockSimplePowerConduit.NORTH, ElectricScaffoldBlock.NORTH); assertSame(BlockSimplePowerConduit.SOUTH, ElectricScaffoldBlock.SOUTH); @@ -39,7 +41,7 @@ public class NativeBlockContractTest { assertSame(BlockSimplePowerConduit.WEST, ElectricScaffoldBlock.WEST); assertSame(BlockSimplePowerConduit.UP, ElectricScaffoldBlock.UP); assertSame(BlockSimplePowerConduit.DOWN, ElectricScaffoldBlock.DOWN); - for (PathType type : PathType.values()) assertFalse(block.allowsMovement(state, null, BlockPos.ZERO, type)); + for (PathType type : PathType.values()) assertFalse(block.isPathfindable(state, null, BlockPos.ZERO, type)); } @Test public void scaffoldInheritsSharedPlacementAndNetworkCallbacks() throws Exception { @@ -48,18 +50,18 @@ public class NativeBlockContractTest { assertSame(BlockSimplePowerConduit.class, scaffold.getMethod("getStateForPlacement", BlockItemUseContext.class).getDeclaringClass()); assertSame(BlockSimplePowerConduit.class, - scaffold.getMethod("updatePostPlacement", BlockState.class, Direction.class, BlockState.class, + scaffold.getMethod("updateShape", BlockState.class, Direction.class, BlockState.class, IWorld.class, BlockPos.class, BlockPos.class).getDeclaringClass()); assertSame(BlockSimplePowerConduit.class, scaffold.getMethod("canAcceptConnection", PowerConnectorContext.class).getDeclaringClass()); assertSame(ConduitBlock.class, - scaffold.getMethod("onBlockAdded", BlockState.class, World.class, BlockPos.class, + scaffold.getMethod("onPlace", BlockState.class, World.class, BlockPos.class, BlockState.class, boolean.class).getDeclaringClass()); assertSame(ConduitBlock.class, - scaffold.getMethod("onReplaced", BlockState.class, World.class, BlockPos.class, + scaffold.getMethod("onRemove", BlockState.class, World.class, BlockPos.class, BlockState.class, boolean.class).getDeclaringClass()); assertSame(ConduitBlock.class, - scaffold.getMethod("onExplosionDestroy", World.class, BlockPos.class, Explosion.class).getDeclaringClass()); + scaffold.getMethod("wasExploded", World.class, BlockPos.class, Explosion.class).getDeclaringClass()); ElectricScaffoldBlock block = new ElectricScaffoldBlock(); assertEquals(1, block.getTypes().length); assertSame(Power.ELECTRIC_POWER, block.getTypes()[0]); @@ -68,15 +70,15 @@ public class NativeBlockContractTest { } @Test public void customMachinePropertiesKeepDrillAndBothTurretsNonSolid() { - assertFalse(new ElectricDrillBlock().getDefaultState().isSolid()); - assertFalse(new LaserTurretBlock(false).getDefaultState().isSolid()); - assertFalse(new LaserTurretBlock(true).getDefaultState().isSolid()); + assertFalse(new ElectricDrillBlock().defaultBlockState().canOcclude()); + assertFalse(new LaserTurretBlock(false).defaultBlockState().canOcclude()); + assertFalse(new LaserTurretBlock(true).defaultBlockState().canOcclude()); } @Test public void hiddenPumpPipeRemainsNonSolidAndSolarPanelRemainsSolid() { - assertFalse(new PumpPipeBlock().getDefaultState().isSolid()); + assertFalse(new PumpPipeBlock().defaultBlockState().canOcclude()); PhotovoltaicGeneratorBlock panel = new PhotovoltaicGeneratorBlock(); - assertTrue("The 1.14 photovoltaic block explicitly overrides isSolid to true", panel.getDefaultState().isSolid()); - assertTrue(panel.isNormalCube(panel.getDefaultState(), null, BlockPos.ZERO)); + assertTrue("The 1.14 photovoltaic block explicitly overrides isSolid to true", panel.defaultBlockState().canOcclude()); + assertTrue(panel.defaultBlockState().isRedstoneConductor(net.minecraft.world.EmptyBlockReader.INSTANCE, BlockPos.ZERO)); } } diff --git a/src/test/java/zone/moddev/mc/electricadvantage/blocks/OreHarvestContractTest.java b/src/test/java/zone/moddev/mc/electricadvantage/blocks/OreHarvestContractTest.java new file mode 100644 index 0000000..28c6f5c --- /dev/null +++ b/src/test/java/zone/moddev/mc/electricadvantage/blocks/OreHarvestContractTest.java @@ -0,0 +1,64 @@ +package zone.moddev.mc.electricadvantage.blocks; + +import com.mojang.authlib.GameProfile; +import java.lang.reflect.Field; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Bootstrap; +import net.minecraft.world.EmptyBlockReader; +import net.minecraftforge.common.ForgeHooks; +import net.minecraftforge.common.ToolType; +import org.junit.BeforeClass; +import org.junit.Test; +import sun.misc.Unsafe; +import static org.junit.Assert.*; + +public class OreHarvestContractTest { + @BeforeClass public static void bootstrapNativeRegistries() { Bootstrap.bootStrap(); } + + @Test public void lithiumRetainsStonePickaxeMinimumThroughNativeHarvestChecks() throws Exception { + BlockState lithium = new Ore(1).defaultBlockState(); + assertTrue(lithium.requiresCorrectToolForDrops()); + assertSame(ToolType.PICKAXE, lithium.getHarvestTool()); + assertEquals(1, lithium.getHarvestLevel()); + assertFalse(canHarvest(lithium, ItemStack.EMPTY)); + assertFalse(canHarvest(lithium, new ItemStack(Items.WOODEN_PICKAXE))); + assertFalse(canHarvest(lithium, new ItemStack(Items.STONE_AXE))); + assertTrue(canHarvest(lithium, new ItemStack(Items.STONE_PICKAXE))); + assertTrue(canHarvest(lithium, new ItemStack(Items.IRON_PICKAXE))); + } + + @Test public void sulfurRetainsWoodenPickaxeMinimumThroughNativeHarvestChecks() throws Exception { + BlockState sulfur = new Ore(new ItemStack(Items.GUNPOWDER), 0, 3).defaultBlockState(); + assertTrue(sulfur.requiresCorrectToolForDrops()); + assertSame(ToolType.PICKAXE, sulfur.getHarvestTool()); + assertEquals(0, sulfur.getHarvestLevel()); + assertFalse(canHarvest(sulfur, ItemStack.EMPTY)); + assertFalse(canHarvest(sulfur, new ItemStack(Items.WOODEN_AXE))); + assertTrue(canHarvest(sulfur, new ItemStack(Items.WOODEN_PICKAXE))); + assertTrue(canHarvest(sulfur, new ItemStack(Items.STONE_PICKAXE))); + } + + private static boolean canHarvest(BlockState state, ItemStack held) throws Exception { + Field field = Unsafe.class.getDeclaredField("theUnsafe"); + field.setAccessible(true); + HarvestPlayer player = (HarvestPlayer) ((Unsafe) field.get(null)).allocateInstance(HarvestPlayer.class); + player.held = held; + return ForgeHooks.canHarvestBlock(state, player, EmptyBlockReader.INSTANCE, BlockPos.ZERO); + } + + // Only omit world construction. Harvest eligibility still executes Forge's native hook. + private static final class HarvestPlayer extends PlayerEntity { + private ItemStack held; + private HarvestPlayer() { super(null, BlockPos.ZERO, 0, (GameProfile) null); } + @Override public ItemStack getMainHandItem() { return held; } + @Override public boolean hasCorrectToolForDrops(BlockState state) { + return !state.requiresCorrectToolForDrops() || held.isCorrectToolForDrops(state); + } + @Override public boolean isSpectator() { return false; } + @Override public boolean isCreative() { return false; } + } +} diff --git a/src/test/java/zone/moddev/mc/electricadvantage/entities/HydroturbinePersistenceTest.java b/src/test/java/zone/moddev/mc/electricadvantage/entities/HydroturbinePersistenceTest.java index 7d07da3..389c5cb 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/entities/HydroturbinePersistenceTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/entities/HydroturbinePersistenceTest.java @@ -15,9 +15,9 @@ public class HydroturbinePersistenceTest { source.putIntArray("parentPos", new int[] {164, 81, 8}); for (int pass = 0; pass < 3; pass++) { HydroturbineEntity turbine = withoutWorld(); - turbine.readAdditional(source); + turbine.readAdditionalSaveData(source); CompoundNBT saved = new CompoundNBT(); - turbine.writeAdditional(saved); + turbine.addAdditionalSaveData(saved); assertArrayEquals(new int[] {164, 81, 8}, saved.getIntArray("parentPos")); source = saved; } @@ -27,20 +27,20 @@ public class HydroturbinePersistenceTest { HydroturbineEntity turbine = withoutWorld(); CompoundNBT source = new CompoundNBT(); source.putIntArray("parentPos", new int[] {164, 81, 8}); - turbine.readAdditional(source); - turbine.readAdditional(new CompoundNBT()); + turbine.readAdditionalSaveData(source); + turbine.readAdditionalSaveData(new CompoundNBT()); CompoundNBT saved = new CompoundNBT(); - turbine.writeAdditional(saved); + turbine.addAdditionalSaveData(saved); assertFalse(saved.contains("parentPos", 11)); } @Test public void savesAttachedGeneratorUsingTheSameLegacyCoordinateKey() throws Exception { HydroturbineEntity turbine = withoutWorld(); HydroelectricGeneratorTileEntity generator = new HydroelectricGeneratorTileEntity(); - generator.setPos(new BlockPos(31, 72, -18)); + generator.setPosition(new BlockPos(31, 72, -18)); turbine.parent = generator; CompoundNBT saved = new CompoundNBT(); - turbine.writeAdditional(saved); + turbine.addAdditionalSaveData(saved); assertArrayEquals(new int[] {31, 72, -18}, saved.getIntArray("parentPos")); } @@ -48,9 +48,9 @@ public class HydroturbinePersistenceTest { HydroturbineEntity turbine = withoutWorld(); CompoundNBT source = new CompoundNBT(); source.putIntArray("parentPos", new int[] {31, 72}); - turbine.readAdditional(source); + turbine.readAdditionalSaveData(source); CompoundNBT saved = new CompoundNBT(); - turbine.writeAdditional(saved); + turbine.addAdditionalSaveData(saved); assertFalse(saved.contains("parentPos", 11)); } diff --git a/src/test/java/zone/moddev/mc/electricadvantage/graphics/RendererBufferContractTest.java b/src/test/java/zone/moddev/mc/electricadvantage/graphics/RendererBufferContractTest.java index 8e8e423..97fa9c3 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/graphics/RendererBufferContractTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/graphics/RendererBufferContractTest.java @@ -6,9 +6,9 @@ import java.util.ArrayList; import java.util.List; import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.util.math.vector.Matrix4f; import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.Vector3f; +import net.minecraft.util.math.vector.Vector3f; import net.minecraft.util.Direction; import net.minecraft.util.registry.Bootstrap; import org.junit.BeforeClass; @@ -26,13 +26,13 @@ public class RendererBufferContractTest { private static final int FULL_BRIGHT = 15 << 20 | 15 << 4; @BeforeClass public static void bootstrapNativeRegistries() { - Bootstrap.register(); + Bootstrap.bootStrap(); } @Test public void quadNormalsUseWindingAndTheNativeNormalMatrix() { MatrixStack matrices = new MatrixStack(); matrices.translate(3, 4, 5); - matrices.rotate(Vector3f.YP.rotationDegrees(90)); + matrices.mulPose(Vector3f.YP.rotationDegrees(90)); RecordingBuffer buffer = new RecordingBuffer(); BufferedQuads quads = new BufferedQuads(matrices, buffer, 0x123456, 0x789abc); quad(quads, false); @@ -59,18 +59,18 @@ public class RendererBufferContractTest { set(ElectricDrillTileEntity.class, drill, "facingCache", direction); MatrixStack matrices = new MatrixStack(); matrices.translate(11, -5, 7); - MatrixStack.Entry before = matrices.getLast(); - Matrix4f matrix = before.getMatrix().copy(); + MatrixStack.Entry before = matrices.last(); + Matrix4f matrix = before.pose().copy(); RecordingBuffer buffer = new RecordingBuffer(); renderer.render(drill, 0.5F, matrices, buffer, 0, 17); - assertSame(before, matrices.getLast()); - assertEquals(matrix, matrices.getLast().getMatrix()); + assertSame(before, matrices.last()); + assertEquals(matrix, matrices.last().pose()); assertTrue(matrices.clear()); assertEquals(direction.toString(), 16, buffer.vertices.size()); assertArrayEquals(new float[] {11.5F, -4.5F, 7.5F}, midpoint(buffer.vertices.get(0), buffer.vertices.get(3)), 0.00001F); - assertArrayEquals(new float[] {11.5F + direction.getXOffset() * 5, - -4.5F + direction.getYOffset() * 5, 7.5F + direction.getZOffset() * 5}, + assertArrayEquals(new float[] {11.5F + direction.getStepX() * 5, + -4.5F + direction.getStepY() * 5, 7.5F + direction.getStepZ() * 5}, midpoint(buffer.vertices.get(1), buffer.vertices.get(2)), 0.00001F); for (Vertex vertex : buffer.vertices) { assertEquals(FULL_BRIGHT, vertex.light); @@ -83,10 +83,10 @@ public class RendererBufferContractTest { @Test public void idleDrillDoesNotTouchTheStackOrEmitVertices() { MatrixStack matrices = new MatrixStack(); - MatrixStack.Entry before = matrices.getLast(); + MatrixStack.Entry before = matrices.last(); RecordingBuffer buffer = new RecordingBuffer(); new LaserDrillRenderer(null).render(new ElectricDrillTileEntity(), 0, matrices, buffer, 0, 0); - assertSame(before, matrices.getLast()); + assertSame(before, matrices.last()); assertTrue(matrices.clear()); assertTrue(buffer.vertices.isEmpty()); } @@ -100,14 +100,14 @@ public class RendererBufferContractTest { for (int charge : new int[] {0, 1, 10, 11}) { set(LaserTurretTileEntity.class, turret, "laserAttack", charge); MatrixStack matrices = new MatrixStack(); - MatrixStack.Entry before = matrices.getLast(); - Matrix4f matrix = before.getMatrix().copy(); + MatrixStack.Entry before = matrices.last(); + Matrix4f matrix = before.pose().copy(); RecordingBuffer buffer = new RecordingBuffer(); renderer.render(turret, 0.5F, matrices, buffer, 0x340012, 23); boolean beam = charge == 1 || charge == 10; assertEquals(beam ? 40 : 24, buffer.vertices.size()); - assertSame(before, matrices.getLast()); - assertEquals(matrix, before.getMatrix()); + assertSame(before, matrices.last()); + assertEquals(matrix, before.pose()); assertTrue(matrices.clear()); assertArrayEquals(new float[] {0.5F, 0.5F}, buffer.vertices.get(0).uv, 0F); assertArrayEquals(new float[] {1, 1}, buffer.vertices.get(2).uv, 0F); @@ -182,11 +182,11 @@ private static final class RecordingBuffer implements IVertexBuilder, IRenderTyp final List vertices = new ArrayList<>(); Vertex vertex = new Vertex(); @Override public IVertexBuilder getBuffer(RenderType type) { return this; } - @Override public IVertexBuilder pos(double x, double y, double z) { vertex.position = new float[] {(float) x, (float) y, (float) z}; return this; } + @Override public IVertexBuilder vertex(double x, double y, double z) { vertex.position = new float[] {(float) x, (float) y, (float) z}; return this; } @Override public IVertexBuilder color(int r, int g, int b, int a) { vertex.color = new int[] {r, g, b, a}; return this; } - @Override public IVertexBuilder tex(float u, float v) { vertex.uv = new float[] {u, v}; return this; } - @Override public IVertexBuilder overlay(int u, int v) { vertex.overlay = u | v << 16; return this; } - @Override public IVertexBuilder lightmap(int u, int v) { vertex.light = u | v << 16; return this; } + @Override public IVertexBuilder uv(float u, float v) { vertex.uv = new float[] {u, v}; return this; } + @Override public IVertexBuilder overlayCoords(int u, int v) { vertex.overlay = u | v << 16; return this; } + @Override public IVertexBuilder uv2(int u, int v) { vertex.light = u | v << 16; return this; } @Override public IVertexBuilder normal(float x, float y, float z) { vertex.normal = new float[] {x, y, z}; return this; } @Override public void endVertex() { vertices.add(vertex); vertex = new Vertex(); } } diff --git a/src/test/java/zone/moddev/mc/electricadvantage/init/VillagesTest.java b/src/test/java/zone/moddev/mc/electricadvantage/init/VillagesTest.java index 3ce2b76..491bbb2 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/init/VillagesTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/init/VillagesTest.java @@ -10,7 +10,7 @@ public class VillagesTest { @BeforeClass public static void bootstrapVanillaItems() { - Bootstrap.register(); + Bootstrap.bootStrap(); } @Test public void nativeNegativePricesKeepBulkGoodsForOneEmerald() { @@ -33,7 +33,7 @@ private static void assertOffer(int minimum, int maximum, boolean upper, int eme }; MerchantOffer offer = Villages.sell(net.minecraft.item.Items.APPLE, minimum, maximum) .getOffer(null, random); - CompoundNBT nbt = offer.write(); + CompoundNBT nbt = offer.createTag(); assertEquals("minecraft:emerald", nbt.getCompound("buy").getString("id")); assertEquals(emeralds, nbt.getCompound("buy").getByte("Count")); assertEquals("minecraft:apple", nbt.getCompound("sell").getString("id")); diff --git a/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricDrillPersistenceTest.java b/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricDrillPersistenceTest.java index c09b57f..f9996cd 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricDrillPersistenceTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricDrillPersistenceTest.java @@ -4,26 +4,30 @@ import net.minecraft.nbt.ListNBT; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Bootstrap; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashSet; import java.util.Set; import org.junit.Test; +import org.junit.BeforeClass; import static org.junit.Assert.assertEquals; public class ElectricDrillPersistenceTest { + @BeforeClass public static void bootstrapNativeRegistries() { Bootstrap.bootStrap(); } + @Test public void retainsLegacyProgressUntilWorldIsAttached() { ElectricDrillTileEntity drill = new ElectricDrillTileEntity(); - drill.read(target(94)); + drill.load(new ElectricDrillBlock().defaultBlockState(), target(94)); drill.prepareDataFieldsForSync(); assertEquals(94, drill.getDataFieldArray()[1]); } @Test public void clearsPreviousProgressOnReadingAnUntargetedTile() { ElectricDrillTileEntity drill = new ElectricDrillTileEntity(); - drill.read(target(94)); - drill.read(new CompoundNBT()); + drill.load(new ElectricDrillBlock().defaultBlockState(), target(94)); + drill.load(new ElectricDrillBlock().defaultBlockState(), new CompoundNBT()); drill.prepareDataFieldsForSync(); assertEquals(0, drill.getDataFieldArray()[1]); } @@ -59,9 +63,9 @@ public class ElectricDrillPersistenceTest { assertEquals(center, targets[0]); for (BlockPos target : targets) { unique.add(target); - assertEquals(0, (target.getX() - center.getX()) * direction.getXOffset() - + (target.getY() - center.getY()) * direction.getYOffset() - + (target.getZ() - center.getZ()) * direction.getZOffset()); + assertEquals(0, (target.getX() - center.getX()) * direction.getStepX() + + (target.getY() - center.getY()) * direction.getStepY() + + (target.getZ() - center.getZ()) * direction.getStepZ()); } assertEquals(direction.toString(), 9, unique.size()); } @@ -69,7 +73,7 @@ public class ElectricDrillPersistenceTest { @Test public void nativeDataFieldsRetainEnergyAndMiningProgress() { ElectricDrillTileEntity drill = new ElectricDrillTileEntity(); - drill.read(target(94)); + drill.load(new ElectricDrillBlock().defaultBlockState(), target(94)); drill.setEnergy(416.0F, drill.getEnergyType()); drill.prepareDataFieldsForSync(); assertEquals(416.0F, Float.intBitsToFloat(drill.getDataFieldArray()[0]), 0.0F); diff --git a/src/test/java/zone/moddev/mc/electricadvantage/machines/LaserTurretGeometryTest.java b/src/test/java/zone/moddev/mc/electricadvantage/machines/LaserTurretGeometryTest.java index 13a48e3..e1def17 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/machines/LaserTurretGeometryTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/machines/LaserTurretGeometryTest.java @@ -2,16 +2,16 @@ import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import org.junit.Test; import static org.junit.Assert.*; public class LaserTurretGeometryTest { @Test public void nativeRayGeometryKeepsHitsInAllSixDirections() { - Vec3d origin = new Vec3d(0.5D, 0.5D, 0.5D); + Vector3d origin = new Vector3d(0.5D, 0.5D, 0.5D); for (Direction facing : Direction.values()) { - Vec3d direction = new Vec3d(facing.getXOffset(), facing.getYOffset(), facing.getZOffset()); - Vec3d center = origin.add(direction.scale(5.0D)); + Vector3d direction = new Vector3d(facing.getStepX(), facing.getStepY(), facing.getStepZ()); + Vector3d center = origin.add(direction.scale(5.0D)); AxisAlignedBB target = new AxisAlignedBB(center.x - 0.25D, center.y - 0.25D, center.z - 0.25D, center.x + 0.25D, center.y + 0.25D, center.z + 0.25D); assertTrue(facing.toString(), LaserTurretTileEntity.rayIntersectsBoundingBox(origin, direction, target)); @@ -20,8 +20,8 @@ public class LaserTurretGeometryTest { } @Test public void anOffsetTargetIsNotHitAndMissingBoundsAreIgnored() { - Vec3d origin = new Vec3d(0.5D, 0.5D, 0.5D); - Vec3d direction = new Vec3d(1.0D, 0.0D, 0.0D); + Vector3d origin = new Vector3d(0.5D, 0.5D, 0.5D); + Vector3d direction = new Vector3d(1.0D, 0.0D, 0.0D); assertFalse(LaserTurretTileEntity.rayIntersectsBoundingBox(origin, direction, new AxisAlignedBB(5.0D, 4.0D, 4.0D, 6.0D, 5.0D, 5.0D))); assertFalse(LaserTurretTileEntity.rayIntersectsBoundingBox(origin, direction, null)); diff --git a/src/test/java/zone/moddev/mc/electricadvantage/migration/ElectricLegacyMigrationsTest.java b/src/test/java/zone/moddev/mc/electricadvantage/migration/ElectricLegacyMigrationsTest.java index 0d34ccf..de29e94 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/migration/ElectricLegacyMigrationsTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/migration/ElectricLegacyMigrationsTest.java @@ -9,7 +9,7 @@ public class ElectricLegacyMigrationsTest { @Test public void preservesAllSixDrillFacingsAndActiveFlag() { for (Direction facing : Direction.values()) { - int metadata = facing.getIndex() | 8; + int metadata = facing.get3DDataValue() | 8; assertEquals(facing, ElectricLegacyMigrations.legacyDrillFacing(metadata)); assertEquals(true, ElectricLegacyMigrations.legacyDrillActive(metadata)); } diff --git a/src/test/java/zone/moddev/mc/electricadvantage/resources/BlockLootResourceTest.java b/src/test/java/zone/moddev/mc/electricadvantage/resources/BlockLootResourceTest.java index 85d9eba..728dd1b 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/resources/BlockLootResourceTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/resources/BlockLootResourceTest.java @@ -33,8 +33,8 @@ public class BlockLootResourceTest { assertFalse(Files.exists(root.resolve("pump_pipe_electric.json"))); } - @Test public void resourcePackDeclaresTheNativeOneFifteenFormat() throws Exception { - assertEquals(5, read(Paths.get("src/main/resources/pack.mcmeta")) + @Test public void resourcePackDeclaresTheNativeOneSixteenFormat() throws Exception { + assertEquals(6, read(Paths.get("src/main/resources/pack.mcmeta")) .getAsJsonObject("pack").get("pack_format").getAsInt()); } diff --git a/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java index b04e850..92a8986 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java @@ -37,11 +37,15 @@ public class BuildWorkflowContractTest { assertTrue(policy < source.indexOf("repository: MinecraftModDevelopmentMods/OreSpawn")); assertTrue(policy < source.indexOf("repository: MinecraftModDevelopmentMods/BaseMetals")); assertTrue(policy < source.indexOf("repository: MinecraftModDevelopmentMods/PowerAdvantage")); - assertTrue(source.contains("ref: 5613baf876747ed071cb7ad7e2aff4e0ce4f0a03")); - assertTrue(source.contains("ref: ac1781e7cade15045ffe0135077087b4d1722603")); - assertTrue(source.contains("BaseMetals-3.0.2.115021-deobf.jar")); - assertTrue(source.contains("ref: 6666099a734eba16561d98c86f3f4bb1b7c742f7")); - assertTrue(source.contains("branches: [master-1.15.2")); + assertTrue(source.contains("ref: a113e5d767169189f0e35ade1e173a12d550b00e")); + assertTrue(source.contains("ref: 995f6cc4dd2d5eecc628a42e5c43fa5390c24bca")); + assertTrue(source.contains("BaseMetals-3.1.1.116051-deobf.jar")); + assertTrue(source.contains("ref: 098d4625abc8a849bd1a11dcf697b3fee0cade7b")); + assertTrue(source.contains("78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3")); + assertFalse(source.contains("ce90c24c302d0ff3565db2db0c6c94a3b5f21f83")); + assertFalse(source.contains("8BBB03DD7E4AF08A7390A161ED5AA94E292BEE56EF60E550B5512E967E0E9174")); + assertTrue(source.indexOf("- name: Require final PowerAdvantage pin") < source.indexOf("- name: Check out pinned OreSpawn")); + assertTrue(source.contains("branches: [master-1.16.5")); assertFalse(source.contains("master-1.14.4")); } } diff --git a/src/test/java/zone/moddev/mc/electricadvantage/resources/RecipeRegistrationThreadTest.java b/src/test/java/zone/moddev/mc/electricadvantage/resources/RecipeRegistrationThreadTest.java index 296975d..e7ffab3 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/resources/RecipeRegistrationThreadTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/resources/RecipeRegistrationThreadTest.java @@ -27,8 +27,8 @@ public class RecipeRegistrationThreadTest { MethodInsnNode call = (MethodInsnNode) instruction; assertFalse("Forge's condition HashMap is not safe during parallel loading", call.owner.equals(conditions) && call.name.equals("register")); - if (call.owner.equals("net/minecraftforge/fml/DeferredWorkQueue") - && call.name.equals("runLater") && registrationRunnable) { + if (call.owner.equals("net/minecraftforge/fml/event/lifecycle/FMLCommonSetupEvent") + && call.name.equals("enqueueWork") && registrationRunnable) { assertEquals("Register conditions during common setup", "commonSetup", method.name); queued++; registrationRunnable = false; diff --git a/tools/verification/AuditedJUnit.java b/tools/verification/AuditedJUnit.java new file mode 100644 index 0000000..79c8789 --- /dev/null +++ b/tools/verification/AuditedJUnit.java @@ -0,0 +1,55 @@ +package zone.moddev.mc.electricadvantage.verification; + +import java.io.FileOutputStream; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamWriter; +import org.junit.internal.TextListener; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; + +/** Reports skipped and assumed tests separately from JUnit's success exit code. */ +public final class AuditedJUnit { + private AuditedJUnit() {} + + public static void main(String[] args) throws Exception { + int expected = Integer.parseInt(args[1]); + Class[] suites = new Class[args.length - 2]; + for (int i = 0; i < suites.length; i++) suites[i] = Class.forName(args[i + 2]); + final int[] assumptions = {0}; + JUnitCore core = new JUnitCore(); + core.addListener(new TextListener(System.out)); + core.addListener(new RunListener() { + @Override public void testAssumptionFailure(Failure failure) { assumptions[0]++; } + }); + Result result = core.run(suites); + boolean passed = result.wasSuccessful() && result.getRunCount() == expected + && result.getIgnoreCount() == 0 && assumptions[0] == 0; + try (FileOutputStream output = new FileOutputStream(args[0])) { + XMLStreamWriter xml = XMLOutputFactory.newFactory().createXMLStreamWriter(output, "UTF-8"); + xml.writeStartDocument("UTF-8", "1.0"); + xml.writeStartElement("testsuite"); + xml.writeAttribute("name", "ElectricAdvantage-bootstrap-B-ECJ"); + xml.writeAttribute("tests", Integer.toString(result.getRunCount())); + xml.writeAttribute("failures", Integer.toString(result.getFailureCount())); + xml.writeAttribute("ignored", Integer.toString(result.getIgnoreCount())); + xml.writeAttribute("assumptions", Integer.toString(assumptions[0])); + xml.writeAttribute("expected", Integer.toString(expected)); + xml.writeAttribute("passed", Boolean.toString(passed)); + for (Failure failure : result.getFailures()) { + xml.writeStartElement("failure"); + xml.writeAttribute("test", failure.getDescription().getDisplayName()); + xml.writeCharacters(failure.getTrace()); + xml.writeEndElement(); + } + xml.writeEndElement(); + xml.writeEndDocument(); + xml.close(); + } + System.out.println("AUDITED_JUNIT tests=" + result.getRunCount() + " expected=" + expected + + " failures=" + result.getFailureCount() + " ignored=" + result.getIgnoreCount() + + " assumptions=" + assumptions[0] + " passed=" + passed); + if (!passed) System.exit(1); + } +} diff --git a/tools/verification/Verify-ElectricEcj.ps1 b/tools/verification/Verify-ElectricEcj.ps1 new file mode 100644 index 0000000..4ff9350 --- /dev/null +++ b/tools/verification/Verify-ElectricEcj.ps1 @@ -0,0 +1,146 @@ +param( + [string]$ProjectRoot = (Join-Path $PSScriptRoot '../..'), + [Parameter(Mandatory = $true)][string]$Evidence, + [string]$Compiler = 'C:/Users/johnb/.p2/pool/plugins/org.eclipse.jdt.core.compiler.batch_3.46.0.v20260528-0407.jar', + [string]$Java17Home = 'C:/Users/johnb/.jdks/temurin-17.0.1+12/jdk-17.0.1+12', + [string]$Java8Home = 'C:/Users/johnb/.jdks/temurin-8.0.502+7/jdk8u502-b07' +) +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version Latest +$ProjectRoot = (Resolve-Path -LiteralPath $ProjectRoot).Path +$Evidence = [IO.Path]::GetFullPath($Evidence) +if (!$Evidence.StartsWith($ProjectRoot + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)) { + throw 'ECJ evidence must remain inside the Electric checkout' +} +if (Test-Path -LiteralPath $Evidence) { throw 'Refusing to overwrite ECJ evidence' } +$null = New-Item -ItemType Directory -Path $Evidence + +function Get-Pin([string]$Path) { + $file = Get-Item -LiteralPath $Path + [ordered]@{ path = $file.FullName; sha256 = (Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256).Hash } +} +function Save-Report { + $json = $report | ConvertTo-Json -Depth 15 + [IO.File]::WriteAllText((Join-Path $Evidence 'ecj-results.json'), $json + "`n", [Text.UTF8Encoding]::new($false)) +} +function Test-ClassFiles([string]$Directory) { + $files = @(Get-ChildItem -LiteralPath $Directory -Recurse -File -Filter '*.class') + if (!$files.Count) { throw "ECJ emitted no classes in $Directory" } + foreach ($file in $files) { + $bytes = [IO.File]::ReadAllBytes($file.FullName) + if ($bytes.Length -lt 8 -or $bytes[0] -ne 0xCA -or $bytes[1] -ne 0xFE -or $bytes[2] -ne 0xBA -or $bytes[3] -ne 0xBE) { + throw "Invalid class file: $($file.FullName)" + } + if (($bytes[6] * 256 + $bytes[7]) -ne 52) { throw "Non-Java-8 ECJ output: $($file.FullName)" } + } + return $files.Count +} +function Invoke-Ecj([string]$Name, [string[]]$Sources, [string[]]$Libraries) { + $output = Join-Path $Evidence $Name + $null = New-Item -ItemType Directory -Path $output + $xmlLog = Join-Path $Evidence "$Name.xml" + $arguments = @('-1.8', '-proc:none', '-encoding', 'UTF-8', '-bootclasspath', + ('"' + (($bootLibraries.path -replace '\\', '/') -join ';') + '"'), '-classpath', + ('"' + (($Libraries -replace '\\', '/') -join ';') + '"'), '-d', + ('"' + $output.Replace('\', '/') + '"'), '-log', ('"' + $xmlLog.Replace('\', '/') + '"')) + $arguments += @($Sources | ForEach-Object { '"' + $_.Replace('\', '/') + '"' }) + $argFile = Join-Path $Evidence "$Name.args" + [IO.File]::WriteAllLines($argFile, $arguments, [Text.UTF8Encoding]::new($false)) + & $java17 -Xmx2G -jar $Compiler "@$argFile" *> (Join-Path $Evidence "$Name-compile.log") + $exitCode = $LASTEXITCODE + $entry = [ordered]@{ exitCode = $exitCode; sourceCount = $Sources.Count; output = $output; log = "$Name-compile.log" } + $report.compilations[$Name] = $entry + if ($exitCode -ne 0) { throw "$Name ECJ compilation failed; retain its log and XML diagnostics" } + [xml]$diagnostics = Get-Content -LiteralPath $xmlLog -Raw + $problems = @($diagnostics.SelectNodes('//*[@severity]')) + $entry.errors = @($problems | Where-Object { $_.GetAttribute('severity') -ieq 'ERROR' }).Count + $entry.warnings = @($problems | Where-Object { $_.GetAttribute('severity') -ieq 'WARNING' }).Count + if ($entry.errors) { throw "$Name ECJ XML contains errors" } + $entry.classCount = Test-ClassFiles $output + return $output +} + +$report = [ordered]@{ status = 'RUNNING'; project = $ProjectRoot; evidence = $Evidence + scope = 'Electric B only; fresh ECJ main/test/helper outputs and worldless Java 8 JUnit; no Gradle or Minecraft launch' + compiler = $null; toolchains = $null; libraries = @(); sources = @(); gradleInventory = @() + compilations = [ordered]@{}; junit = $null } +try { + $properties = ConvertFrom-StringData -StringData (Get-Content -LiteralPath (Join-Path $ProjectRoot 'gradle.properties') -Raw) + if ($properties.mod_id -ne 'electricadvantage' -or $properties.mod_version -ne '2.2.8.116051' -or + $properties.poweradvantage_source_ref -ne '098d4625abc8a849bd1a11dcf697b3fee0cade7b' -or + $properties.poweradvantage_deobf_sha256 -ne '78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3') { + throw 'This verifier is pinned to the Electric 1.16.5 bootstrap-B candidate' + } + $report.compiler = Get-Pin $Compiler + if ($report.compiler.sha256 -ne 'D0D43F8E2D7003E5EFED612E2CBB5F01870043397D8F1BBE536FD9128F4FCBF7') { throw 'ECJ compiler pin mismatch' } + $java17 = Join-Path $Java17Home 'bin/java.exe' + $java8 = Join-Path $Java8Home 'bin/java.exe' + $bootLibraries = @(Get-ChildItem -LiteralPath (Join-Path $Java8Home 'jre/lib') -File -Filter '*.jar' | Sort-Object Name | ForEach-Object { Get-Pin $_.FullName }) + if (!(($bootLibraries.path | Split-Path -Leaf) -contains 'rt.jar')) { throw 'Missing Java 8 boot runtime' } + $report.toolchains = [ordered]@{ compilerJava = (Get-Pin $java17); runtimeJava = (Get-Pin $java8) + java17Release = (Get-Pin (Join-Path $Java17Home 'release')); java8Release = (Get-Pin (Join-Path $Java8Home 'release')); bootLibraries = $bootLibraries } + [xml]$classpath = Get-Content -LiteralPath (Join-Path $ProjectRoot '.classpath') -Raw + $report.classpath = Get-Pin (Join-Path $ProjectRoot '.classpath') + $mainLibraries = @() + $testLibraries = @() + foreach ($entry in @($classpath.classpath.classpathentry | Where-Object { $_.kind -eq 'lib' })) { + $file = if ([IO.Path]::IsPathRooted([string]$entry.path)) { [IO.Path]::GetFullPath([string]$entry.path) } + else { [IO.Path]::GetFullPath((Join-Path $ProjectRoot ([string]$entry.path))) } + if ([IO.Path]::GetFileName($file) -like 'ElectricAdvantage*.jar') { throw 'Electric output jar cannot satisfy its own ECJ compilation' } + $scopeNode = $entry.SelectSingleNode('attributes/attribute[@name="gradle_used_by_scope"]/@value') + $scope = if ($scopeNode) { $scopeNode.Value } else { '' } + $pin = Get-Pin $file + $pin.scope = $scope + $report.libraries += $pin + if (!$scope -or $scope.Split(',') -contains 'main') { $mainLibraries += $file } + if (!$scope -or $scope.Split(',') -contains 'test') { $testLibraries += $file } + } + foreach ($dependency in @(@{ prefix = 'PowerAdvantage-'; hash = $properties.poweradvantage_deobf_sha256 }, + @{ prefix = 'BaseMetals-'; hash = $properties.basemetals_deobf_sha256 }, @{ prefix = 'OreSpawn-'; hash = $properties.orespawn_deobf_sha256 })) { + $matching = @($report.libraries | Where-Object { [IO.Path]::GetFileName($_.path).StartsWith($dependency.prefix) }) + if ($matching.Count -ne 1 -or $matching[0].sha256 -ne $dependency.hash) { throw "Typed dependency pin mismatch: $($dependency.prefix)" } + } + $sources = @{} + foreach ($set in @('main', 'test')) { + $sources[$set] = @(Get-ChildItem -LiteralPath (Join-Path $ProjectRoot "src/$set/java") -Recurse -File -Filter '*.java' | Sort-Object FullName | ForEach-Object { $_.FullName }) + $report.sources += @($sources[$set] | ForEach-Object { Get-Pin $_ }) + } + $classes = @() + $expected = 0 + foreach ($xml in @(Get-ChildItem -LiteralPath (Join-Path $ProjectRoot 'build/test-results/test') -File -Filter 'TEST-*.xml' | Sort-Object Name)) { + [xml]$inventory = Get-Content -LiteralPath $xml.FullName -Raw + if ([int]$inventory.testsuite.failures -or [int]$inventory.testsuite.errors -or [int]$inventory.testsuite.skipped) { throw 'Gradle suite inventory contains failed/skipped tests' } + $classes += [string]$inventory.testsuite.name + $expected += [int]$inventory.testsuite.tests + $report.gradleInventory += Get-Pin $xml.FullName + } + if ($classes.Count -ne 17 -or $expected -ne 47 -or $sources.test.Count -ne 17 -or $sources.main.Count -ne 85) { throw 'Unexpected Electric B source/test inventory' } + $main = Invoke-Ecj 'main' $sources.main $mainLibraries + $test = Invoke-Ecj 'test' $sources.test (@($main) + $testLibraries) + $helperSource = Join-Path $PSScriptRoot 'AuditedJUnit.java' + $report.helper = Get-Pin $helperSource + $helper = Invoke-Ecj 'helper' @($helperSource) $testLibraries + $junitXml = Join-Path $Evidence 'junit.xml' + $runtime = @($main, $test, $helper, (Join-Path $ProjectRoot 'build/resources/main'), (Join-Path $ProjectRoot 'build/resources/test')) + $testLibraries + $report.runtime = $runtime + Push-Location $ProjectRoot + try { + & $java8 -Xmx2G -cp ($runtime -join ';') zone.moddev.mc.electricadvantage.verification.AuditedJUnit $junitXml $expected @classes *> (Join-Path $Evidence 'junit.log') + $junitExit = $LASTEXITCODE + } finally { Pop-Location } + $report.junit = [ordered]@{ exitCode = $junitExit; expected = $expected; suites = $classes; log = 'junit.log'; xml = 'junit.xml' } + if ($junitExit -ne 0) { throw 'Fresh ECJ JUnit execution failed' } + [xml]$junit = Get-Content -LiteralPath $junitXml -Raw + if ($junit.testsuite.passed -ne 'true' -or [int]$junit.testsuite.tests -ne $expected -or + [int]$junit.testsuite.failures -or [int]$junit.testsuite.ignored -or [int]$junit.testsuite.assumptions) { throw 'Strict ECJ test counts failed' } + foreach ($pin in @($report.sources) + @($report.libraries) + @($report.helper)) { + if ((Get-FileHash -LiteralPath $pin.path -Algorithm SHA256).Hash -ne $pin.sha256) { throw "Input changed during ECJ qualification: $($pin.path)" } + } + $report.status = 'PASS' +} catch { + $report.status = 'FAIL' + $report.error = $_.ToString() + throw +} finally { Save-Report } +Get-Content -LiteralPath (Join-Path $Evidence 'junit.log') -Tail 8 +Write-Output "ECJ PASS: $($sources.main.Count) main, $($sources.test.Count) test sources; $expected tests; Java 8 class files" diff --git a/tools/verify-native-port.js b/tools/verify-native-port.js new file mode 100644 index 0000000..29e2c61 --- /dev/null +++ b/tools/verify-native-port.js @@ -0,0 +1,115 @@ +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); +const { execFileSync } = require('node:child_process'); + +const root = path.resolve(__dirname, '..'); +const baseline = '74aa1cee1ddec821ebcd12b9f8b0515b7aec61d9'; +const javaRoot = 'src/main/java/zone/moddev/mc/electricadvantage/'; +const read = name => fs.readFileSync(path.join(root, name), 'utf8'); +const git = (...args) => execFileSync('git', args, { cwd: root }); +const tracked = git('ls-tree', '-r', '--name-only', baseline).toString().trim().split('\n'); +const results = []; +function check(name, run) { + try { run(); results.push({ name, passed: true }); } + catch (error) { results.push({ name, passed: false, error: error.message }); } +} +function strings(source) { + const tokens = source.match(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\/\/[^\n]*|\/\*[\s\S]*?\*\//g) || []; + return tokens.filter(token => token.startsWith('"')) + .filter(token => token !== '"2.2.7.115021"' && token !== '"2.2.8.116051"').sort(); +} +function numbers(source) { + const tokens = source.match(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\/\/[^\n]*|\/\*[\s\S]*?\*\/|[A-Za-z_$][A-Za-z0-9_$]*|(?:0[xX][\da-fA-F_]+|(?:\d[\d_]*\.?[\d_]*|\.\d[\d_]*)(?:[eE][+-]?[\d_]+)?)[dDfFlL]?/g) || []; + return tokens.filter(token => /^\d|^\.\d/.test(token)); +} + +check('Exact native target metadata', () => { + const properties = read('gradle.properties'); + for (const pair of ['minecraft_version=1.16.5', 'forge_version=36.2.34', + 'mapping_channel=official', 'mapping_version=1.16.5', 'mcp_version=20210115.111550', + 'mod_version=2.2.8.116051', 'poweradvantage_version=2.4.7.116051', + 'poweradvantage_source_ref=098d4625abc8a849bd1a11dcf697b3fee0cade7b', + 'poweradvantage_deobf_sha256=78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3', + 'basemetals_version=3.1.1.116051', 'orespawn_version=4.1.0.116051', + 'java_version=8', 'gradle_java_version=17']) { + assert(properties.split(/\r?\n/).includes(pair), pair); + } + assert.equal(JSON.parse(read('src/main/resources/pack.mcmeta')).pack.pack_format, 6); +}); +check('115 assets, recipes, tags, loot, and unlock bytes are unchanged', () => { + for (const name of tracked.filter(name => name.startsWith('src/main/resources/') + && !['src/main/resources/pack.mcmeta', 'src/main/resources/META-INF/mods.toml'].includes(name))) { + assert.deepEqual(fs.readFileSync(path.join(root, name)), git('show', `${baseline}:${name}`), name); + } +}); +check('Production string identities and NBT keys match the accepted 115 source', () => { + for (const name of tracked.filter(name => name.startsWith(javaRoot) && name.endsWith('.java'))) { + assert.deepEqual(strings(read(name)), strings(git('show', `${baseline}:${name}`).toString()), name); + } +}); +check('Production numeric constants and rendering test tolerances match 115', () => { + const rendererTest = 'src/test/java/zone/moddev/mc/electricadvantage/graphics/RendererBufferContractTest.java'; + for (const name of tracked.filter(name => name.startsWith(javaRoot) && name.endsWith('.java') || name === rendererTest)) { + assert.deepEqual(numbers(read(name)), numbers(git('show', `${baseline}:${name}`).toString()), name); + } +}); +check('Tag entries use native values rather than a legacy optional array', () => { + for (const name of tracked.filter(name => name.includes('/tags/') && name.endsWith('.json'))) { + const tag = JSON.parse(read(name)); + assert(!Object.hasOwn(tag, 'optional'), name); + assert(Array.isArray(tag.values), name); + for (const value of tag.values) { + assert(typeof value === 'string' || value && typeof value.id === 'string' + && (!Object.hasOwn(value, 'required') || typeof value.required === 'boolean'), name); + } + } +}); +check('World-only conduit callbacks and native solar dimension type', () => { + const drill = read(javaRoot + 'machines/ElectricDrillBlock.java'); + const tile = read(javaRoot + 'machines/ElectricDrillTileEntity.java'); + assert(!/dimension\.getType|\.getId\(\)/.test(drill + tile)); + assert.match(drill, /conduitBlockPlacedEvent\(\s*world, pos, Power\.ELECTRIC_POWER\)/); + assert.match(tile, /conduitBlockRemovedEvent\(getLevel\(\), getBlockPos\(\), getEnergyType\(\)\)/); + assert(read(javaRoot + 'machines/PhotovoltaicGeneratorTileEntity.java').includes('dimensionType().hasSkyLight()')); +}); +check('Native persistence overrides and state-aware turret updates', () => { + for (const name of ['ElectricMachineTileEntity', 'ElectricGeneratorTileEntity', 'GrowthChamberControllerTileEntity']) { + const source = read(javaRoot + `machines/${name}.java`); + assert.match(source, /void load\((?:net\.minecraft\.block\.)?BlockState state, (?:final )?CompoundNBT tagRoot\)/); + assert(source.includes('super.load(state, tagRoot)')); + assert.match(source, /CompoundNBT save\(/); + assert(source.includes('super.save(tagRoot)')); + } + assert.match(read(javaRoot + 'machines/LaserTurretTileEntity.java'), /handleUpdateTag\(BlockState state, CompoundNBT tag\)/); +}); +check('Native mining prerequisite and serialized recipe registration', () => { + assert.equal((read(javaRoot + 'blocks/Ore.java').match(/requiresCorrectToolForDrops\(\)/g) || []).length, 2); + assert(read(javaRoot + 'ElectricAdvantage.java').includes('event.enqueueWork(RecipeConditions::register)')); + assert(!read(javaRoot + 'ElectricAdvantage.java').includes('DeferredWorkQueue.runLater')); +}); +check('Custom fluid API and parent inventory names are preserved', () => { + assert(read(javaRoot + 'util/LegacyFluidHandler.java').includes('extends IAdvantageFluidHandler')); + assert(read(javaRoot + 'machines/ElectricPumpTileEntity.java').includes('getTank().getFluid().getFluid()')); + assert(read(javaRoot + 'machines/ElectricMachineTileEntity.java').includes('ItemStack[] getInventory()')); + assert(!tracked.filter(name => name.startsWith(javaRoot) && name.endsWith('.java')) + .some(name => /invalidateCaps\(|reviveCaps\(|LazyOptional/.test(read(name)))); +}); +check('Native renderer format and inherited tracking settings', () => { + const render = read(javaRoot + 'graphics/ElectricRenderTypes.java'); + assert(render.includes('DefaultVertexFormats.NEW_ENTITY')); + assert(render.includes('NO_DIFFUSE_LIGHTING')); + const entities = read(javaRoot + 'init/Entities.java'); + assert(entities.includes('.setTrackingRange(64).setUpdateInterval(1).setShouldReceiveVelocityUpdates(true)')); +}); + +const report = { baseline, scope: 'Static source/resource contracts only; no compilation or Minecraft runtime', results }; +const reportFlag = process.argv.indexOf('--report'); +if (reportFlag !== -1) { + const output = path.resolve(root, process.argv[reportFlag + 1]); + assert(output.startsWith(root + path.sep), 'Report must remain inside this checkout'); + fs.mkdirSync(path.dirname(output), { recursive: true }); + fs.writeFileSync(output, JSON.stringify(report, null, 2) + '\n'); +} +for (const result of results) console.log(`${result.passed ? 'PASS' : 'FAIL'} ${result.name}${result.error ? ': ' + result.error : ''}`); +process.exitCode = results.every(result => result.passed) ? 0 : 1; From b0cdfad2ec4afe362f38f6afab2da46378f338a0 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 13:50:26 +0000 Subject: [PATCH 02/12] Pin Electric 1.16.5 to Power bootstrap C --- .github/workflows/ci.yml | 4 +- .github/workflows/codeql-analysis.yml | 4 +- CHANGELOG.txt | 4 +- README.md | 20 ++++---- build.gradle | 4 +- docs/NATIVE116.md | 48 ++++++++++++++++--- gradle.properties | 4 +- .../resources/BuildWorkflowContractTest.java | 6 ++- tools/verification/AuditedJUnit.java | 2 +- tools/verification/Verify-ElectricEcj.ps1 | 10 ++-- tools/verify-native-port.js | 4 +- 11 files changed, 74 insertions(+), 36 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa94c41..313e506 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: set -euo pipefail power_ref="$(sed -n 's/^poweradvantage_source_ref=//p' gradle.properties | tr -d '\r')" power_sha="$(sed -n 's/^poweradvantage_deobf_sha256=//p' gradle.properties | tr -d '\r')" - if [[ "$power_ref" != "098d4625abc8a849bd1a11dcf697b3fee0cade7b" || "$power_sha" != "78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3" ]]; then + if [[ "$power_ref" != "e72fc3c39dab98fe2fb7b6a9105e0173585d6001" || "$power_sha" != "C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B" ]]; then echo "PowerAdvantage 1.16.5 source/deobf pin differs from the audited candidate" >&2 exit 1 fi @@ -53,7 +53,7 @@ jobs: with: repository: MinecraftModDevelopmentMods/PowerAdvantage # Local-only Power source; publish upstream before hosted builds. - ref: 098d4625abc8a849bd1a11dcf697b3fee0cade7b + ref: e72fc3c39dab98fe2fb7b6a9105e0173585d6001 path: .ci-dependencies/PowerAdvantage - name: Install pinned Java 25 Mavenizer runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b011263..12306f6 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -31,7 +31,7 @@ jobs: set -euo pipefail power_ref="$(sed -n 's/^poweradvantage_source_ref=//p' gradle.properties | tr -d '\r')" power_sha="$(sed -n 's/^poweradvantage_deobf_sha256=//p' gradle.properties | tr -d '\r')" - if [[ "$power_ref" != "098d4625abc8a849bd1a11dcf697b3fee0cade7b" || "$power_sha" != "78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3" ]]; then + if [[ "$power_ref" != "e72fc3c39dab98fe2fb7b6a9105e0173585d6001" || "$power_sha" != "C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B" ]]; then echo "PowerAdvantage 1.16.5 source/deobf pin differs from the audited candidate" >&2 exit 1 fi @@ -53,7 +53,7 @@ jobs: with: repository: MinecraftModDevelopmentMods/PowerAdvantage # Local-only Power source; publish upstream before hosted builds. - ref: 098d4625abc8a849bd1a11dcf697b3fee0cade7b + ref: e72fc3c39dab98fe2fb7b6a9105e0173585d6001 path: .ci-dependencies/PowerAdvantage - name: Install pinned Java 25 Mavenizer runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 2c2a903..471095e 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -5,8 +5,8 @@ Electric Advantage 2.2.8.116051 (local port candidate) - Use native renderer buffers, state-aware tile persistence and world-only Power Advantage conduit callbacks. - Retain lithium/sulfur mining levels through native correct-tool checks and serialize recipe-condition registration with enqueueWork. - Preserve registry IDs, legacy aliases, NBT keys, balance constants, recipes, discoveries and asset bytes from the accepted 1.15 source. -- Pin the exact local Power Advantage 2.4.7.116051 bootstrap-B source/development artifact; retain fail-closed release audits and no dependency embedding. -- Pass local production/test compilation, all 47 Java tests, release audits and Eclipse production-classpath checks. +- Pin the exact local Power Advantage 2.4.7.116051 bootstrap-C source/development artifact; retain fail-closed release audits and no dependency embedding. +- Pass all 47 Java tests, release audits, Eclipse and independent ECJ checks against C; preserve prior A/B build evidence and failed D actor evidence. - Keep packaged runtime qualification, world-upgrade checks and manual acceptance pending. Electric Advantage 2.2.7.115021 diff --git a/README.md b/README.md index 08d2554..1d51b37 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ # Electric Advantage -**Minecraft 1.16.5 port candidate, version 2.2.8.116051.** Compilation, all 47 Java -tests, release audits and Eclipse checks passed locally against Power bootstrap B. -Bootstrap-A evidence is preserved separately. Packaged runtime -qualification and manual acceptance are pending; this is not a published -release. See [the native port checklist](docs/NATIVE116.md). +**Minecraft 1.16.5 port candidate, version 2.2.8.116051.** Local compilation, all +47 Java tests, release audits, Eclipse checks and fresh ECJ compilation pass +against Power bootstrap C. Earlier A/B build evidence and the failed D actor +campaign are preserved separately. C's packaged runtime qualification and manual +acceptance remain pending. This is not a published release. +See [the native port checklist](docs/NATIVE116.md). The [accepted 1.15 record](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.15.2/docs/1.15/CURRENT-QUALIFICATION.md) is a behavior reference, not evidence that this target passes. @@ -22,12 +23,12 @@ inference and downloads. Build inputs are separate, non-embedded deobfuscated jars: -- Power Advantage `2.4.7.116051`: source `098d4625abc8a849bd1a11dcf697b3fee0cade7b`. +- Power Advantage `2.4.7.116051`: source `e72fc3c39dab98fe2fb7b6a9105e0173585d6001`. - Base Metals `3.1.1.116051`: source `995f6cc4dd2d5eecc628a42e5c43fa5390c24bca`. - OreSpawn `4.1.0.116051`: source `a113e5d767169189f0e35ade1e173a12d550b00e`. Exact checksums are recorded in `gradle.properties`. Power deobf SHA-256 is -`78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3`. +`C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B`. Its source is local-only; hosted reproducibility is pending upstream source publication. Do not bypass the release audits or substitute a preliminary jar. Use immutable copies for verification, not a sibling's output that another @@ -45,8 +46,9 @@ The complete deterministic release gates are: gradlew.bat clean check build javadoc verifyReleaseDependencies verifyReleaseArtifacts writeReleaseChecksums verifyEclipseProductionClasspath ``` -These gates passed locally on 27 October 2026 against the pinned immutable -dependencies. They do not replace packaged client/server tests, +These gates passed locally on 27 October 2026 against the exact immutable C +inputs, with all 47 tests rerun and no build-cache reuse. The independent ECJ +run also passed all 47 tests on Java 8. These results do not replace packaged client/server tests, disposable-world migration checks or manual acceptance. Do not run another build concurrently against a shared Gradle cache. diff --git a/build.gradle b/build.gradle index 257db3f..57d3796 100644 --- a/build.gradle +++ b/build.gradle @@ -377,8 +377,8 @@ tasks.register('verifyReleaseConfiguration') { } if (project.poweradvantage_version != '2.4.7.116051' || project.poweradvantage_source_repository != 'MinecraftModDevelopmentMods/PowerAdvantage' - || project.poweradvantage_source_ref != '098d4625abc8a849bd1a11dcf697b3fee0cade7b' - || project.poweradvantage_deobf_sha256 != '78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3') { + || project.poweradvantage_source_ref != 'e72fc3c39dab98fe2fb7b6a9105e0173585d6001' + || project.poweradvantage_deobf_sha256 != 'C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B') { throw new GradleException('Unexpected PowerAdvantage compile dependency identity') } if (project.basemetals_version != '3.1.1.116051' diff --git a/docs/NATIVE116.md b/docs/NATIVE116.md index b34b191..64871a6 100644 --- a/docs/NATIVE116.md +++ b/docs/NATIVE116.md @@ -12,9 +12,9 @@ checks and manual acceptance. Only checks actually executed may be marked passed - Base deobf SHA-256: `A7B0C4F394DFAF4E11E0275B1A86CB1D47C7AF8E175759D9BB84F965C684466D`. - OreSpawn `4.1.0.116051`, source `a113e5d767169189f0e35ade1e173a12d550b00e`. - OreSpawn deobf SHA-256: `DCEE75480C9DD70EE58B218AAE799C5FAB0525DAF9A05455270F1570C24F7F8F`. -- Power bootstrap B source: `098d4625abc8a849bd1a11dcf697b3fee0cade7b` (local-only). -- Power bootstrap B deobf SHA-256: `78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3`. -- Verified immutable Power release SHA-256: `60E10F94F447D948244EF088A3B77134C13FBEBCCA1D8DB6210E8630F94A051F`. +- Power bootstrap C source: `e72fc3c39dab98fe2fb7b6a9105e0173585d6001` (local-only). +- Power bootstrap C deobf SHA-256: `C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B`. +- Verified immutable Power release SHA-256: `DBE2226C4A1FE505A94A411EA68540CAEC40186598847BAB936CE16EC8E2FA01`. Copy the final verified jars to immutable local input paths before building. Do not compile against a sibling output that another worker may overwrite. @@ -80,7 +80,9 @@ parent's constructor-time GUI matrix initialization; it does not change the API. ### Bootstrap B Revalidation -The exact B source/deobf pins above are configured. The clean full suite passed +This historical run used Power source `098d4625abc8a849bd1a11dcf697b3fee0cade7b` +and deobf SHA-256 `78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3`. +The clean full suite passed against the immutable B jar on 27 October 2026 with `--rerun-tasks` and `--no-build-cache`: production/test compilation, all 47 Java tests (zero failures, errors or skips), release configuration/dependency/artifact/checksum audits and @@ -95,6 +97,38 @@ Frozen B artifacts are under `evidence/native116-bootstrap-b-candidate`. The A reports, handoff and candidate directory remain unchanged. The B handoff is `evidence/native116-bootstrap-b-handoff.json`. +### Bootstrap C Revalidation + +The active pins above select the parent's frozen local C source and immutable +artifact. C contains native registry, entity migration and capability fixes. +The C clean full suite passed on 27 October 2026 in 49 seconds with +`--rerun-tasks --no-build-cache`: all 47 Java tests in 17 suites, zero failures, +errors or skips, release configuration/dependency/artifact/checksum audits and +production Eclipse generation/classpath checks. The exclusively leased cache +was already warm; this is not a new cold-cache claim. + +Fresh ECJ compilation passed for 85 main sources, 17 test sources and the strict +JUnit helper. All 47 tests passed on Java 8 with zero ignored or assumed tests; +every emitted class uses major version 52. The existing 52 main-source compiler +warnings remain visible. The ten static contracts and all 50 recipe unlocks pass. + +The raw runtime, deobf and sources jars are byte-identical to frozen B. The +Javadoc jar differs in 18 HTML pages because Power C adds inherited +`areCapabilitiesValid` and changes the declaring owner of `reviveCaps`. +The Javadoc difference is recorded, not normalized away. C Javadoc SHA-256 is +`AB9EBF1BB5A79AE576AF12A25D186D2662EEAD2C79FB4F9A8A5475F776376D4D`. +Raw archive hashes and entry-level diagnostics are under +`evidence/native116-bootstrap-c-20261027-01/`; prior A/B evidence is unchanged. + +The previous D actor attempt is INCOMPLETE FAIL: five direct routes retained +wolf UUID/owner and hydroturbine UUID failures; the chained113 route failed the +strict registry/async-save ERROR gate on boot 16. Its raw audit and all source +custody remain preserved under `evidence/native116_actor_d_20261027/` and the +parent's test-rig. No strict identity, item or health oracle was relaxed. +The prepared 108-boot matrix remains pending sealed E inputs and a new runtime +lease. Dedicated native114 actor-origin fixtures remain unqualified; a native115 +actor extension needs explicit stopped-source custody, not an old destination PASS. + Remaining runtime and acceptance work, only under an explicit runtime lease: 1. Test the packaged candidate's recipes, @@ -109,6 +143,6 @@ Remaining runtime and acceptance work, only under an explicit runtime lease: 5. Manually inspect all GUIs, textures, beam directions/lighting, turret controls, hydroturbine orientation/spin, sounds, interaction and multiplayer behavior. -No Minecraft runtime, packaged smoke, world-upgrade pass -or manual acceptance is claimed. Commits, pushes, PRs, -tags and releases are outside the current authorization. +No C Minecraft runtime, packaged smoke, world-upgrade pass or manual acceptance +is claimed. A local-only commit of the C repin and checks is authorized; pushes, +PRs, tags and releases remain unauthorized. diff --git a/gradle.properties b/gradle.properties index f663a51..99a7711 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,8 +38,8 @@ cf_versions=1.16.5 poweradvantage_version=2.4.7.116051 poweradvantage_source_repository=MinecraftModDevelopmentMods/PowerAdvantage # Exact local-only Power source and immutable development artifact; publish source before hosted builds. -poweradvantage_source_ref=098d4625abc8a849bd1a11dcf697b3fee0cade7b -poweradvantage_deobf_sha256=78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3 +poweradvantage_source_ref=e72fc3c39dab98fe2fb7b6a9105e0173585d6001 +poweradvantage_deobf_sha256=C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B basemetals_version=3.1.1.116051 basemetals_source_commit=995f6cc4dd2d5eecc628a42e5c43fa5390c24bca diff --git a/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java index 92a8986..ab19cbd 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java @@ -40,8 +40,10 @@ public class BuildWorkflowContractTest { assertTrue(source.contains("ref: a113e5d767169189f0e35ade1e173a12d550b00e")); assertTrue(source.contains("ref: 995f6cc4dd2d5eecc628a42e5c43fa5390c24bca")); assertTrue(source.contains("BaseMetals-3.1.1.116051-deobf.jar")); - assertTrue(source.contains("ref: 098d4625abc8a849bd1a11dcf697b3fee0cade7b")); - assertTrue(source.contains("78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3")); + assertTrue(source.contains("ref: e72fc3c39dab98fe2fb7b6a9105e0173585d6001")); + assertTrue(source.contains("C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B")); + assertFalse(source.contains("098d4625abc8a849bd1a11dcf697b3fee0cade7b")); + assertFalse(source.contains("78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3")); assertFalse(source.contains("ce90c24c302d0ff3565db2db0c6c94a3b5f21f83")); assertFalse(source.contains("8BBB03DD7E4AF08A7390A161ED5AA94E292BEE56EF60E550B5512E967E0E9174")); assertTrue(source.indexOf("- name: Require final PowerAdvantage pin") < source.indexOf("- name: Check out pinned OreSpawn")); diff --git a/tools/verification/AuditedJUnit.java b/tools/verification/AuditedJUnit.java index 79c8789..7a325a1 100644 --- a/tools/verification/AuditedJUnit.java +++ b/tools/verification/AuditedJUnit.java @@ -30,7 +30,7 @@ public static void main(String[] args) throws Exception { XMLStreamWriter xml = XMLOutputFactory.newFactory().createXMLStreamWriter(output, "UTF-8"); xml.writeStartDocument("UTF-8", "1.0"); xml.writeStartElement("testsuite"); - xml.writeAttribute("name", "ElectricAdvantage-bootstrap-B-ECJ"); + xml.writeAttribute("name", "ElectricAdvantage-bootstrap-C-ECJ"); xml.writeAttribute("tests", Integer.toString(result.getRunCount())); xml.writeAttribute("failures", Integer.toString(result.getFailureCount())); xml.writeAttribute("ignored", Integer.toString(result.getIgnoreCount())); diff --git a/tools/verification/Verify-ElectricEcj.ps1 b/tools/verification/Verify-ElectricEcj.ps1 index 4ff9350..9da5f86 100644 --- a/tools/verification/Verify-ElectricEcj.ps1 +++ b/tools/verification/Verify-ElectricEcj.ps1 @@ -61,15 +61,15 @@ function Invoke-Ecj([string]$Name, [string[]]$Sources, [string[]]$Libraries) { } $report = [ordered]@{ status = 'RUNNING'; project = $ProjectRoot; evidence = $Evidence - scope = 'Electric B only; fresh ECJ main/test/helper outputs and worldless Java 8 JUnit; no Gradle or Minecraft launch' + scope = 'Electric C only; fresh ECJ main/test/helper outputs and worldless Java 8 JUnit; no Gradle or Minecraft launch' compiler = $null; toolchains = $null; libraries = @(); sources = @(); gradleInventory = @() compilations = [ordered]@{}; junit = $null } try { $properties = ConvertFrom-StringData -StringData (Get-Content -LiteralPath (Join-Path $ProjectRoot 'gradle.properties') -Raw) if ($properties.mod_id -ne 'electricadvantage' -or $properties.mod_version -ne '2.2.8.116051' -or - $properties.poweradvantage_source_ref -ne '098d4625abc8a849bd1a11dcf697b3fee0cade7b' -or - $properties.poweradvantage_deobf_sha256 -ne '78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3') { - throw 'This verifier is pinned to the Electric 1.16.5 bootstrap-B candidate' + $properties.poweradvantage_source_ref -ne 'e72fc3c39dab98fe2fb7b6a9105e0173585d6001' -or + $properties.poweradvantage_deobf_sha256 -ne 'C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B') { + throw 'This verifier is pinned to the Electric 1.16.5 bootstrap-C candidate' } $report.compiler = Get-Pin $Compiler if ($report.compiler.sha256 -ne 'D0D43F8E2D7003E5EFED612E2CBB5F01870043397D8F1BBE536FD9128F4FCBF7') { throw 'ECJ compiler pin mismatch' } @@ -114,7 +114,7 @@ try { $expected += [int]$inventory.testsuite.tests $report.gradleInventory += Get-Pin $xml.FullName } - if ($classes.Count -ne 17 -or $expected -ne 47 -or $sources.test.Count -ne 17 -or $sources.main.Count -ne 85) { throw 'Unexpected Electric B source/test inventory' } + if ($classes.Count -ne 17 -or $expected -ne 47 -or $sources.test.Count -ne 17 -or $sources.main.Count -ne 85) { throw 'Unexpected Electric C source/test inventory' } $main = Invoke-Ecj 'main' $sources.main $mainLibraries $test = Invoke-Ecj 'test' $sources.test (@($main) + $testLibraries) $helperSource = Join-Path $PSScriptRoot 'AuditedJUnit.java' diff --git a/tools/verify-native-port.js b/tools/verify-native-port.js index 29e2c61..0795ac1 100644 --- a/tools/verify-native-port.js +++ b/tools/verify-native-port.js @@ -29,8 +29,8 @@ check('Exact native target metadata', () => { for (const pair of ['minecraft_version=1.16.5', 'forge_version=36.2.34', 'mapping_channel=official', 'mapping_version=1.16.5', 'mcp_version=20210115.111550', 'mod_version=2.2.8.116051', 'poweradvantage_version=2.4.7.116051', - 'poweradvantage_source_ref=098d4625abc8a849bd1a11dcf697b3fee0cade7b', - 'poweradvantage_deobf_sha256=78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3', + 'poweradvantage_source_ref=e72fc3c39dab98fe2fb7b6a9105e0173585d6001', + 'poweradvantage_deobf_sha256=C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B', 'basemetals_version=3.1.1.116051', 'orespawn_version=4.1.0.116051', 'java_version=8', 'gradle_java_version=17']) { assert(properties.split(/\r?\n/).includes(pair), pair); From 391c1fc48495d0c746d28bba35c92b6e1a15c89c Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 15:46:24 +0000 Subject: [PATCH 03/12] Pin Electric 1.16.5 to Power bootstrap D --- .github/workflows/ci.yml | 4 +-- .github/workflows/codeql-analysis.yml | 4 +-- CHANGELOG.txt | 4 +-- README.md | 13 +++---- build.gradle | 4 +-- docs/NATIVE116.md | 36 ++++++++++++++----- gradle.properties | 4 +-- .../resources/BuildWorkflowContractTest.java | 4 +-- tools/verification/AuditedJUnit.java | 2 +- tools/verification/Verify-ElectricEcj.ps1 | 10 +++--- tools/verify-native-port.js | 4 +-- 11 files changed, 54 insertions(+), 35 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 313e506..4ce0de8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: set -euo pipefail power_ref="$(sed -n 's/^poweradvantage_source_ref=//p' gradle.properties | tr -d '\r')" power_sha="$(sed -n 's/^poweradvantage_deobf_sha256=//p' gradle.properties | tr -d '\r')" - if [[ "$power_ref" != "e72fc3c39dab98fe2fb7b6a9105e0173585d6001" || "$power_sha" != "C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B" ]]; then + if [[ "$power_ref" != "2116a35a40dd150d79e7dfdcdc891637793178b7" || "$power_sha" != "F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A" ]]; then echo "PowerAdvantage 1.16.5 source/deobf pin differs from the audited candidate" >&2 exit 1 fi @@ -53,7 +53,7 @@ jobs: with: repository: MinecraftModDevelopmentMods/PowerAdvantage # Local-only Power source; publish upstream before hosted builds. - ref: e72fc3c39dab98fe2fb7b6a9105e0173585d6001 + ref: 2116a35a40dd150d79e7dfdcdc891637793178b7 path: .ci-dependencies/PowerAdvantage - name: Install pinned Java 25 Mavenizer runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 12306f6..4611be8 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -31,7 +31,7 @@ jobs: set -euo pipefail power_ref="$(sed -n 's/^poweradvantage_source_ref=//p' gradle.properties | tr -d '\r')" power_sha="$(sed -n 's/^poweradvantage_deobf_sha256=//p' gradle.properties | tr -d '\r')" - if [[ "$power_ref" != "e72fc3c39dab98fe2fb7b6a9105e0173585d6001" || "$power_sha" != "C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B" ]]; then + if [[ "$power_ref" != "2116a35a40dd150d79e7dfdcdc891637793178b7" || "$power_sha" != "F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A" ]]; then echo "PowerAdvantage 1.16.5 source/deobf pin differs from the audited candidate" >&2 exit 1 fi @@ -53,7 +53,7 @@ jobs: with: repository: MinecraftModDevelopmentMods/PowerAdvantage # Local-only Power source; publish upstream before hosted builds. - ref: e72fc3c39dab98fe2fb7b6a9105e0173585d6001 + ref: 2116a35a40dd150d79e7dfdcdc891637793178b7 path: .ci-dependencies/PowerAdvantage - name: Install pinned Java 25 Mavenizer runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 471095e..3a2e641 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -5,8 +5,8 @@ Electric Advantage 2.2.8.116051 (local port candidate) - Use native renderer buffers, state-aware tile persistence and world-only Power Advantage conduit callbacks. - Retain lithium/sulfur mining levels through native correct-tool checks and serialize recipe-condition registration with enqueueWork. - Preserve registry IDs, legacy aliases, NBT keys, balance constants, recipes, discoveries and asset bytes from the accepted 1.15 source. -- Pin the exact local Power Advantage 2.4.7.116051 bootstrap-C source/development artifact; retain fail-closed release audits and no dependency embedding. -- Pass all 47 Java tests, release audits, Eclipse and independent ECJ checks against C; preserve prior A/B build evidence and failed D actor evidence. +- Pin the exact local Power Advantage 2.4.7.116051 bootstrap-D source/development artifact; retain fail-closed release audits and no dependency embedding. +- Pass all 47 Gradle and 47 fresh ECJ tests plus release/Eclipse audits against D; archive all four raw jars, byte-identical to C, without relabelling prior evidence. - Keep packaged runtime qualification, world-upgrade checks and manual acceptance pending. Electric Advantage 2.2.7.115021 diff --git a/README.md b/README.md index 1d51b37..1e59cc4 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,9 @@ **Minecraft 1.16.5 port candidate, version 2.2.8.116051.** Local compilation, all 47 Java tests, release audits, Eclipse checks and fresh ECJ compilation pass -against Power bootstrap C. Earlier A/B build evidence and the failed D actor -campaign are preserved separately. C's packaged runtime qualification and manual +against frozen Power D. All four archived Electric jars are byte-identical to C. +Earlier A/B/C evidence and failed or partial actor +campaigns are preserved separately. Packaged runtime qualification and manual acceptance remain pending. This is not a published release. See [the native port checklist](docs/NATIVE116.md). The [accepted 1.15 record](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.15.2/docs/1.15/CURRENT-QUALIFICATION.md) @@ -23,12 +24,12 @@ inference and downloads. Build inputs are separate, non-embedded deobfuscated jars: -- Power Advantage `2.4.7.116051`: source `e72fc3c39dab98fe2fb7b6a9105e0173585d6001`. +- Power Advantage `2.4.7.116051`: source `2116a35a40dd150d79e7dfdcdc891637793178b7`. - Base Metals `3.1.1.116051`: source `995f6cc4dd2d5eecc628a42e5c43fa5390c24bca`. - OreSpawn `4.1.0.116051`: source `a113e5d767169189f0e35ade1e173a12d550b00e`. Exact checksums are recorded in `gradle.properties`. Power deobf SHA-256 is -`C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B`. +`F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A`. Its source is local-only; hosted reproducibility is pending upstream source publication. Do not bypass the release audits or substitute a preliminary jar. Use immutable copies for verification, not a sibling's output that another @@ -46,8 +47,8 @@ The complete deterministic release gates are: gradlew.bat clean check build javadoc verifyReleaseDependencies verifyReleaseArtifacts writeReleaseChecksums verifyEclipseProductionClasspath ``` -These gates passed locally on 27 October 2026 against the exact immutable C -inputs, with all 47 tests rerun and no build-cache reuse. The independent ECJ +These gates passed locally on 27 October 2026 against immutable D inputs, +with all 47 tests rerun and no build-cache reuse. The independent ECJ run also passed all 47 tests on Java 8. These results do not replace packaged client/server tests, disposable-world migration checks or manual acceptance. Do not run another build concurrently against a shared Gradle cache. diff --git a/build.gradle b/build.gradle index 57d3796..16467f5 100644 --- a/build.gradle +++ b/build.gradle @@ -377,8 +377,8 @@ tasks.register('verifyReleaseConfiguration') { } if (project.poweradvantage_version != '2.4.7.116051' || project.poweradvantage_source_repository != 'MinecraftModDevelopmentMods/PowerAdvantage' - || project.poweradvantage_source_ref != 'e72fc3c39dab98fe2fb7b6a9105e0173585d6001' - || project.poweradvantage_deobf_sha256 != 'C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B') { + || project.poweradvantage_source_ref != '2116a35a40dd150d79e7dfdcdc891637793178b7' + || project.poweradvantage_deobf_sha256 != 'F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A') { throw new GradleException('Unexpected PowerAdvantage compile dependency identity') } if (project.basemetals_version != '3.1.1.116051' diff --git a/docs/NATIVE116.md b/docs/NATIVE116.md index 64871a6..1b7f6bf 100644 --- a/docs/NATIVE116.md +++ b/docs/NATIVE116.md @@ -12,9 +12,9 @@ checks and manual acceptance. Only checks actually executed may be marked passed - Base deobf SHA-256: `A7B0C4F394DFAF4E11E0275B1A86CB1D47C7AF8E175759D9BB84F965C684466D`. - OreSpawn `4.1.0.116051`, source `a113e5d767169189f0e35ade1e173a12d550b00e`. - OreSpawn deobf SHA-256: `DCEE75480C9DD70EE58B218AAE799C5FAB0525DAF9A05455270F1570C24F7F8F`. -- Power bootstrap C source: `e72fc3c39dab98fe2fb7b6a9105e0173585d6001` (local-only). -- Power bootstrap C deobf SHA-256: `C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B`. -- Verified immutable Power release SHA-256: `DBE2226C4A1FE505A94A411EA68540CAEC40186598847BAB936CE16EC8E2FA01`. +- Power bootstrap D source: `2116a35a40dd150d79e7dfdcdc891637793178b7` (local-only). +- Power bootstrap D deobf SHA-256: `F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A`. +- Verified immutable Power release SHA-256: `94C36D3F157A120943C067D4317D1C55D62792BAB43E309640DB64BAEE3FFE7E`. Copy the final verified jars to immutable local input paths before building. Do not compile against a sibling output that another worker may overwrite. @@ -99,8 +99,10 @@ reports, handoff and candidate directory remain unchanged. The B handoff is ### Bootstrap C Revalidation -The active pins above select the parent's frozen local C source and immutable -artifact. C contains native registry, entity migration and capability fixes. +This historical run used frozen local C source +`e72fc3c39dab98fe2fb7b6a9105e0173585d6001` and deobf SHA-256 +`C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B`. +C contains native registry, entity migration and capability fixes. The C clean full suite passed on 27 October 2026 in 49 seconds with `--rerun-tasks --no-build-cache`: all 47 Java tests in 17 suites, zero failures, errors or skips, release configuration/dependency/artifact/checksum audits and @@ -125,8 +127,9 @@ wolf UUID/owner and hydroturbine UUID failures; the chained113 route failed the strict registry/async-save ERROR gate on boot 16. Its raw audit and all source custody remain preserved under `evidence/native116_actor_d_20261027/` and the parent's test-rig. No strict identity, item or health oracle was relaxed. -The prepared 108-boot matrix remains pending sealed E inputs and a new runtime -lease. Dedicated native114 actor-origin fixtures remain unqualified; a native115 +The F actor/storage attempt is retained as interrupted baseline-only evidence, +not final qualification. A new 108-boot matrix needs sealed G inputs and a new +runtime lease. Dedicated native114 actor-origin fixtures remain unqualified; a native115 actor extension needs explicit stopped-source custody, not an old destination PASS. Remaining runtime and acceptance work, only under an explicit runtime lease: @@ -143,6 +146,21 @@ Remaining runtime and acceptance work, only under an explicit runtime lease: 5. Manually inspect all GUIs, textures, beam directions/lighting, turret controls, hydroturbine orientation/spin, sounds, interaction and multiplayer behavior. -No C Minecraft runtime, packaged smoke, world-upgrade pass or manual acceptance -is claimed. A local-only commit of the C repin and checks is authorized; pushes, +### Bootstrap D Revalidation + +The active pins select the parent's frozen D source and immutable artifact. +D adds native owned-machine item and typed-player item migration fixes. +Electric's clean full suite passed in 47 seconds with all 47 tests in 17 suites, +zero failures/errors/skips, no build-cache reuse, and all release/Eclipse audits. +Fresh ECJ main/test compilation and 47 Java 8 JUnit tests passed with no ignored +or assumed tests; all emitted classes use major version 52. The ten static +contracts and 50 recipe unlocks also pass. The exclusively leased cache was +already warm; this is not a new cold-cache claim. + +All four archived raw Electric jars (runtime, deobf, sources and Javadoc) are +byte-identical to C. Evidence is under `evidence/native116-bootstrap-d-20261027-01/`, +`evidence/native116-ecj-bootstrap-d-root-01/` and +`evidence/native116-bootstrap-d-candidate/`. Prior A/B/C evidence remains unchanged; +no previous result is relabelled as D. No D Minecraft runtime, packaged smoke, world-upgrade pass or +manual acceptance is claimed. A local-only commit of the D repin is authorized; pushes, PRs, tags and releases remain unauthorized. diff --git a/gradle.properties b/gradle.properties index 99a7711..0a00c8e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,8 +38,8 @@ cf_versions=1.16.5 poweradvantage_version=2.4.7.116051 poweradvantage_source_repository=MinecraftModDevelopmentMods/PowerAdvantage # Exact local-only Power source and immutable development artifact; publish source before hosted builds. -poweradvantage_source_ref=e72fc3c39dab98fe2fb7b6a9105e0173585d6001 -poweradvantage_deobf_sha256=C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B +poweradvantage_source_ref=2116a35a40dd150d79e7dfdcdc891637793178b7 +poweradvantage_deobf_sha256=F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A basemetals_version=3.1.1.116051 basemetals_source_commit=995f6cc4dd2d5eecc628a42e5c43fa5390c24bca diff --git a/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java index ab19cbd..ca6e502 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java @@ -40,8 +40,8 @@ public class BuildWorkflowContractTest { assertTrue(source.contains("ref: a113e5d767169189f0e35ade1e173a12d550b00e")); assertTrue(source.contains("ref: 995f6cc4dd2d5eecc628a42e5c43fa5390c24bca")); assertTrue(source.contains("BaseMetals-3.1.1.116051-deobf.jar")); - assertTrue(source.contains("ref: e72fc3c39dab98fe2fb7b6a9105e0173585d6001")); - assertTrue(source.contains("C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B")); + assertTrue(source.contains("ref: 2116a35a40dd150d79e7dfdcdc891637793178b7")); + assertTrue(source.contains("F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A")); assertFalse(source.contains("098d4625abc8a849bd1a11dcf697b3fee0cade7b")); assertFalse(source.contains("78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3")); assertFalse(source.contains("ce90c24c302d0ff3565db2db0c6c94a3b5f21f83")); diff --git a/tools/verification/AuditedJUnit.java b/tools/verification/AuditedJUnit.java index 7a325a1..765a37d 100644 --- a/tools/verification/AuditedJUnit.java +++ b/tools/verification/AuditedJUnit.java @@ -30,7 +30,7 @@ public static void main(String[] args) throws Exception { XMLStreamWriter xml = XMLOutputFactory.newFactory().createXMLStreamWriter(output, "UTF-8"); xml.writeStartDocument("UTF-8", "1.0"); xml.writeStartElement("testsuite"); - xml.writeAttribute("name", "ElectricAdvantage-bootstrap-C-ECJ"); + xml.writeAttribute("name", "ElectricAdvantage-bootstrap-D-ECJ"); xml.writeAttribute("tests", Integer.toString(result.getRunCount())); xml.writeAttribute("failures", Integer.toString(result.getFailureCount())); xml.writeAttribute("ignored", Integer.toString(result.getIgnoreCount())); diff --git a/tools/verification/Verify-ElectricEcj.ps1 b/tools/verification/Verify-ElectricEcj.ps1 index 9da5f86..2eccdac 100644 --- a/tools/verification/Verify-ElectricEcj.ps1 +++ b/tools/verification/Verify-ElectricEcj.ps1 @@ -61,15 +61,15 @@ function Invoke-Ecj([string]$Name, [string[]]$Sources, [string[]]$Libraries) { } $report = [ordered]@{ status = 'RUNNING'; project = $ProjectRoot; evidence = $Evidence - scope = 'Electric C only; fresh ECJ main/test/helper outputs and worldless Java 8 JUnit; no Gradle or Minecraft launch' + scope = 'Electric D only; fresh ECJ main/test/helper outputs and worldless Java 8 JUnit; no Gradle or Minecraft launch' compiler = $null; toolchains = $null; libraries = @(); sources = @(); gradleInventory = @() compilations = [ordered]@{}; junit = $null } try { $properties = ConvertFrom-StringData -StringData (Get-Content -LiteralPath (Join-Path $ProjectRoot 'gradle.properties') -Raw) if ($properties.mod_id -ne 'electricadvantage' -or $properties.mod_version -ne '2.2.8.116051' -or - $properties.poweradvantage_source_ref -ne 'e72fc3c39dab98fe2fb7b6a9105e0173585d6001' -or - $properties.poweradvantage_deobf_sha256 -ne 'C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B') { - throw 'This verifier is pinned to the Electric 1.16.5 bootstrap-C candidate' + $properties.poweradvantage_source_ref -ne '2116a35a40dd150d79e7dfdcdc891637793178b7' -or + $properties.poweradvantage_deobf_sha256 -ne 'F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A') { + throw 'This verifier is pinned to the Electric 1.16.5 bootstrap-D candidate' } $report.compiler = Get-Pin $Compiler if ($report.compiler.sha256 -ne 'D0D43F8E2D7003E5EFED612E2CBB5F01870043397D8F1BBE536FD9128F4FCBF7') { throw 'ECJ compiler pin mismatch' } @@ -114,7 +114,7 @@ try { $expected += [int]$inventory.testsuite.tests $report.gradleInventory += Get-Pin $xml.FullName } - if ($classes.Count -ne 17 -or $expected -ne 47 -or $sources.test.Count -ne 17 -or $sources.main.Count -ne 85) { throw 'Unexpected Electric C source/test inventory' } + if ($classes.Count -ne 17 -or $expected -ne 47 -or $sources.test.Count -ne 17 -or $sources.main.Count -ne 85) { throw 'Unexpected Electric D source/test inventory' } $main = Invoke-Ecj 'main' $sources.main $mainLibraries $test = Invoke-Ecj 'test' $sources.test (@($main) + $testLibraries) $helperSource = Join-Path $PSScriptRoot 'AuditedJUnit.java' diff --git a/tools/verify-native-port.js b/tools/verify-native-port.js index 0795ac1..edb4951 100644 --- a/tools/verify-native-port.js +++ b/tools/verify-native-port.js @@ -29,8 +29,8 @@ check('Exact native target metadata', () => { for (const pair of ['minecraft_version=1.16.5', 'forge_version=36.2.34', 'mapping_channel=official', 'mapping_version=1.16.5', 'mcp_version=20210115.111550', 'mod_version=2.2.8.116051', 'poweradvantage_version=2.4.7.116051', - 'poweradvantage_source_ref=e72fc3c39dab98fe2fb7b6a9105e0173585d6001', - 'poweradvantage_deobf_sha256=C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B', + 'poweradvantage_source_ref=2116a35a40dd150d79e7dfdcdc891637793178b7', + 'poweradvantage_deobf_sha256=F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A', 'basemetals_version=3.1.1.116051', 'orespawn_version=4.1.0.116051', 'java_version=8', 'gradle_java_version=17']) { assert(properties.split(/\r?\n/).includes(pair), pair); From 61cbe49e513d4063f47a762dc3095b2239c625c2 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 18:07:45 +0000 Subject: [PATCH 04/12] Use the corrected Power dependency for 1.16 validation --- .github/workflows/ci.yml | 4 ++-- .github/workflows/codeql-analysis.yml | 4 ++-- CHANGELOG.txt | 2 +- README.md | 4 ++-- build.gradle | 4 ++-- gradle.properties | 4 ++-- .../resources/BuildWorkflowContractTest.java | 4 ++-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ce0de8..c1a4a23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: set -euo pipefail power_ref="$(sed -n 's/^poweradvantage_source_ref=//p' gradle.properties | tr -d '\r')" power_sha="$(sed -n 's/^poweradvantage_deobf_sha256=//p' gradle.properties | tr -d '\r')" - if [[ "$power_ref" != "2116a35a40dd150d79e7dfdcdc891637793178b7" || "$power_sha" != "F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A" ]]; then + if [[ "$power_ref" != "3f1100e6f75b1fb949cc883be7288aa30789876d" || "$power_sha" != "1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4" ]]; then echo "PowerAdvantage 1.16.5 source/deobf pin differs from the audited candidate" >&2 exit 1 fi @@ -53,7 +53,7 @@ jobs: with: repository: MinecraftModDevelopmentMods/PowerAdvantage # Local-only Power source; publish upstream before hosted builds. - ref: 2116a35a40dd150d79e7dfdcdc891637793178b7 + ref: 3f1100e6f75b1fb949cc883be7288aa30789876d path: .ci-dependencies/PowerAdvantage - name: Install pinned Java 25 Mavenizer runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 4611be8..0a90a42 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -31,7 +31,7 @@ jobs: set -euo pipefail power_ref="$(sed -n 's/^poweradvantage_source_ref=//p' gradle.properties | tr -d '\r')" power_sha="$(sed -n 's/^poweradvantage_deobf_sha256=//p' gradle.properties | tr -d '\r')" - if [[ "$power_ref" != "2116a35a40dd150d79e7dfdcdc891637793178b7" || "$power_sha" != "F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A" ]]; then + if [[ "$power_ref" != "3f1100e6f75b1fb949cc883be7288aa30789876d" || "$power_sha" != "1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4" ]]; then echo "PowerAdvantage 1.16.5 source/deobf pin differs from the audited candidate" >&2 exit 1 fi @@ -53,7 +53,7 @@ jobs: with: repository: MinecraftModDevelopmentMods/PowerAdvantage # Local-only Power source; publish upstream before hosted builds. - ref: 2116a35a40dd150d79e7dfdcdc891637793178b7 + ref: 3f1100e6f75b1fb949cc883be7288aa30789876d path: .ci-dependencies/PowerAdvantage - name: Install pinned Java 25 Mavenizer runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 3a2e641..25b6bd5 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -5,7 +5,7 @@ Electric Advantage 2.2.8.116051 (local port candidate) - Use native renderer buffers, state-aware tile persistence and world-only Power Advantage conduit callbacks. - Retain lithium/sulfur mining levels through native correct-tool checks and serialize recipe-condition registration with enqueueWork. - Preserve registry IDs, legacy aliases, NBT keys, balance constants, recipes, discoveries and asset bytes from the accepted 1.15 source. -- Pin the exact local Power Advantage 2.4.7.116051 bootstrap-D source/development artifact; retain fail-closed release audits and no dependency embedding. +- Pin the Power Advantage 2.4.7.116051 build with the legacy Forge attribute repair; retain fail-closed release audits and keep dependencies out of the jar. - Pass all 47 Gradle and 47 fresh ECJ tests plus release/Eclipse audits against D; archive all four raw jars, byte-identical to C, without relabelling prior evidence. - Keep packaged runtime qualification, world-upgrade checks and manual acceptance pending. diff --git a/README.md b/README.md index 1e59cc4..8109f13 100644 --- a/README.md +++ b/README.md @@ -24,12 +24,12 @@ inference and downloads. Build inputs are separate, non-embedded deobfuscated jars: -- Power Advantage `2.4.7.116051`: source `2116a35a40dd150d79e7dfdcdc891637793178b7`. +- Power Advantage `2.4.7.116051`: source `3f1100e6f75b1fb949cc883be7288aa30789876d`. - Base Metals `3.1.1.116051`: source `995f6cc4dd2d5eecc628a42e5c43fa5390c24bca`. - OreSpawn `4.1.0.116051`: source `a113e5d767169189f0e35ade1e173a12d550b00e`. Exact checksums are recorded in `gradle.properties`. Power deobf SHA-256 is -`F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A`. +`1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4`. Its source is local-only; hosted reproducibility is pending upstream source publication. Do not bypass the release audits or substitute a preliminary jar. Use immutable copies for verification, not a sibling's output that another diff --git a/build.gradle b/build.gradle index 16467f5..60a7bac 100644 --- a/build.gradle +++ b/build.gradle @@ -377,8 +377,8 @@ tasks.register('verifyReleaseConfiguration') { } if (project.poweradvantage_version != '2.4.7.116051' || project.poweradvantage_source_repository != 'MinecraftModDevelopmentMods/PowerAdvantage' - || project.poweradvantage_source_ref != '2116a35a40dd150d79e7dfdcdc891637793178b7' - || project.poweradvantage_deobf_sha256 != 'F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A') { + || project.poweradvantage_source_ref != '3f1100e6f75b1fb949cc883be7288aa30789876d' + || project.poweradvantage_deobf_sha256 != '1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4') { throw new GradleException('Unexpected PowerAdvantage compile dependency identity') } if (project.basemetals_version != '3.1.1.116051' diff --git a/gradle.properties b/gradle.properties index 0a00c8e..8126556 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,8 +38,8 @@ cf_versions=1.16.5 poweradvantage_version=2.4.7.116051 poweradvantage_source_repository=MinecraftModDevelopmentMods/PowerAdvantage # Exact local-only Power source and immutable development artifact; publish source before hosted builds. -poweradvantage_source_ref=2116a35a40dd150d79e7dfdcdc891637793178b7 -poweradvantage_deobf_sha256=F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A +poweradvantage_source_ref=3f1100e6f75b1fb949cc883be7288aa30789876d +poweradvantage_deobf_sha256=1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4 basemetals_version=3.1.1.116051 basemetals_source_commit=995f6cc4dd2d5eecc628a42e5c43fa5390c24bca diff --git a/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java index ca6e502..b873eb5 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java @@ -40,8 +40,8 @@ public class BuildWorkflowContractTest { assertTrue(source.contains("ref: a113e5d767169189f0e35ade1e173a12d550b00e")); assertTrue(source.contains("ref: 995f6cc4dd2d5eecc628a42e5c43fa5390c24bca")); assertTrue(source.contains("BaseMetals-3.1.1.116051-deobf.jar")); - assertTrue(source.contains("ref: 2116a35a40dd150d79e7dfdcdc891637793178b7")); - assertTrue(source.contains("F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A")); + assertTrue(source.contains("ref: 3f1100e6f75b1fb949cc883be7288aa30789876d")); + assertTrue(source.contains("1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4")); assertFalse(source.contains("098d4625abc8a849bd1a11dcf697b3fee0cade7b")); assertFalse(source.contains("78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3")); assertFalse(source.contains("ce90c24c302d0ff3565db2db0c6c94a3b5f21f83")); From e45d982920124627ac89f18304f1860ac35ca185 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 19:45:09 +0000 Subject: [PATCH 05/12] Update the 1.16 build and testing notes --- CHANGELOG.txt | 4 ++-- README.md | 23 +++++++++++++---------- docs/NATIVE116.md | 35 +++++++++++++++++++++++++++-------- 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 25b6bd5..332ef6e 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -6,8 +6,8 @@ Electric Advantage 2.2.8.116051 (local port candidate) - Retain lithium/sulfur mining levels through native correct-tool checks and serialize recipe-condition registration with enqueueWork. - Preserve registry IDs, legacy aliases, NBT keys, balance constants, recipes, discoveries and asset bytes from the accepted 1.15 source. - Pin the Power Advantage 2.4.7.116051 build with the legacy Forge attribute repair; retain fail-closed release audits and keep dependencies out of the jar. -- Pass all 47 Gradle and 47 fresh ECJ tests plus release/Eclipse audits against D; archive all four raw jars, byte-identical to C, without relabelling prior evidence. -- Keep packaged runtime qualification, world-upgrade checks and manual acceptance pending. +- Pass all 47 Java tests with both Gradle and the Eclipse compiler, along with release and Eclipse audits against the pinned dependencies. +- Recheck connected-machine upgrades, recipes, mining, loot and full-restart operation through the shared Advantage Works rig; keep wider migration checks and manual acceptance separate. Electric Advantage 2.2.7.115021 diff --git a/README.md b/README.md index 8109f13..011d91b 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # Electric Advantage -**Minecraft 1.16.5 port candidate, version 2.2.8.116051.** Local compilation, all -47 Java tests, release audits, Eclipse checks and fresh ECJ compilation pass -against frozen Power D. All four archived Electric jars are byte-identical to C. -Earlier A/B/C evidence and failed or partial actor -campaigns are preserved separately. Packaged runtime qualification and manual -acceptance remain pending. This is not a published release. +**Minecraft 1.16.5 port candidate, version 2.2.8.116051.** All 47 Java tests, +release audits, Eclipse checks and independent Eclipse-compiler tests pass +against the pinned Power Advantage build. Combined machine, recipe, mining and +connected-world upgrade checks also pass; wider migration checks are still being +completed. Manual acceptance is pending. This is not a published release. See [the native port checklist](docs/NATIVE116.md). +The [shared test record](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.16.5/docs/1.16/CURRENT-QUALIFICATION.md) +records the exact jars, completed checks and remaining limits. That page will be +available upstream when this local port is merged. The [accepted 1.15 record](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.15.2/docs/1.15/CURRENT-QUALIFICATION.md) is a behavior reference, not evidence that this target passes. @@ -47,7 +49,7 @@ The complete deterministic release gates are: gradlew.bat clean check build javadoc verifyReleaseDependencies verifyReleaseArtifacts writeReleaseChecksums verifyEclipseProductionClasspath ``` -These gates passed locally on 27 October 2026 against immutable D inputs, +These gates passed locally on 27 October 2026 against the pinned inputs, with all 47 tests rerun and no build-cache reuse. The independent ECJ run also passed all 47 tests on Java 8. These results do not replace packaged client/server tests, disposable-world migration checks or manual acceptance. @@ -95,9 +97,10 @@ installation relationship is unchanged. Typed integration uses the matching Base Metals and OreSpawn APIs without embedding either mod. The RF- and Tech Reborn-labelled converters belong to Power Advantage and use -Forge Energy. Visuals, GUI interaction, sound, weapons, hydroturbine behavior, -multiplayer, tag reloads, dimensions and world upgrades need target-specific -verification. No 1.16 publication is authorized before manual acceptance. +Forge Energy. Check live rendering, GUI interaction, sound, weapons, +hydroturbine orientation and animation, multiplayer and real player login in +game. Automated tag, machine and upgrade checks do not replace that walkthrough. +No 1.16 publication is included before manual acceptance. Always back up a whole world before upgrading and test only disposable copies. Keep migration backups and failed evidence. Bounded Advantage results never diff --git a/docs/NATIVE116.md b/docs/NATIVE116.md index 1b7f6bf..54c824b 100644 --- a/docs/NATIVE116.md +++ b/docs/NATIVE116.md @@ -12,9 +12,11 @@ checks and manual acceptance. Only checks actually executed may be marked passed - Base deobf SHA-256: `A7B0C4F394DFAF4E11E0275B1A86CB1D47C7AF8E175759D9BB84F965C684466D`. - OreSpawn `4.1.0.116051`, source `a113e5d767169189f0e35ade1e173a12d550b00e`. - OreSpawn deobf SHA-256: `DCEE75480C9DD70EE58B218AAE799C5FAB0525DAF9A05455270F1570C24F7F8F`. -- Power bootstrap D source: `2116a35a40dd150d79e7dfdcdc891637793178b7` (local-only). -- Power bootstrap D deobf SHA-256: `F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A`. -- Verified immutable Power release SHA-256: `94C36D3F157A120943C067D4317D1C55D62792BAB43E309640DB64BAEE3FFE7E`. +- Power source: `3f1100e6f75b1fb949cc883be7288aa30789876d` (local-only). +- Power deobf SHA-256: `1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4`. +- Power release SHA-256: `EB226ADC200BFB96278F1449CDB7C6941F289DB43330C8206369048378E931EB`. +- Electric source: `61cbe49e513d4063f47a762dc3095b2239c625c2`. +- Electric release SHA-256: `A9B62DD737E42455FEE72BD2D855C9C5EDBF5A9C5EAD7B48C650C9073A35B129`. Copy the final verified jars to immutable local input paths before building. Do not compile against a sibling output that another worker may overwrite. @@ -22,6 +24,23 @@ The release audit retains exact source/hash expectations for this candidate. Do not relax those checks. Publish the local-only Power source upstream before hosted build or release readiness is claimed. +## Current Checks + +All 47 Java tests pass with Gradle and with a fresh Eclipse compiler build on +Java 8. Release, dependency, bytecode, resource and Eclipse classpath audits +pass. All four Electric jars match the independently reproduced earlier build; +the dependency repin changes no Electric class or resource. + +The current packaged jars pass combined Works, recipe modes and unlocks, +survival mining and drops, extended drills, and connected-world operating +checks after upgrades. Current unloading and broader player/entity checks are +tracked in Power Advantage's `docs/1.16/CURRENT-QUALIFICATION.md`; incomplete +cases are not counted as passes. Manual rendering, controls, sounds, weapons, +multiplayer and actual player login still need checking. + +The bootstrap notes below are historical receipts, not current readiness +claims. Failed and interrupted runs remain recorded under their original names. + ## Source Contracts - All recipe, advancement, tag, loot, model, texture and translation resources @@ -132,7 +151,7 @@ not final qualification. A new 108-boot matrix needs sealed G inputs and a new runtime lease. Dedicated native114 actor-origin fixtures remain unqualified; a native115 actor extension needs explicit stopped-source custody, not an old destination PASS. -Remaining runtime and acceptance work, only under an explicit runtime lease: +At that historical checkpoint, runtime and acceptance work remained: 1. Test the packaged candidate's recipes, unlocks, native tags, condition modes, resource reload and restart behavior. @@ -148,7 +167,7 @@ Remaining runtime and acceptance work, only under an explicit runtime lease: ### Bootstrap D Revalidation -The active pins select the parent's frozen D source and immutable artifact. +That historical run selected the parent's frozen D source and immutable artifact. D adds native owned-machine item and typed-player item migration fixes. Electric's clean full suite passed in 47 seconds with all 47 tests in 17 suites, zero failures/errors/skips, no build-cache reuse, and all release/Eclipse audits. @@ -161,6 +180,6 @@ All four archived raw Electric jars (runtime, deobf, sources and Javadoc) are byte-identical to C. Evidence is under `evidence/native116-bootstrap-d-20261027-01/`, `evidence/native116-ecj-bootstrap-d-root-01/` and `evidence/native116-bootstrap-d-candidate/`. Prior A/B/C evidence remains unchanged; -no previous result is relabelled as D. No D Minecraft runtime, packaged smoke, world-upgrade pass or -manual acceptance is claimed. A local-only commit of the D repin is authorized; pushes, -PRs, tags and releases remain unauthorized. +no previous result is relabelled as D. Those build receipts do not claim a D +Minecraft runtime, packaged smoke, world-upgrade pass or manual acceptance. +The current inputs and checks are listed at the top of this page. From 545132cb49596731bd3f1d16808c630ef60cda26 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 19:47:52 +0000 Subject: [PATCH 06/12] Keep verification helpers on the tested Power build --- .../resources/BuildWorkflowContractTest.java | 7 +++++++ tools/verification/Verify-ElectricEcj.ps1 | 10 +++++----- tools/verify-native-port.js | 4 ++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java index b873eb5..eedd0a9 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java @@ -30,6 +30,13 @@ public class BuildWorkflowContractTest { } @Test public void dependencyPolicyPrecedesEveryPinnedCheckout() throws Exception { + for (String helper : new String[] {"tools/verify-native-port.js", "tools/verification/Verify-ElectricEcj.ps1"}) { + String source = new String(Files.readAllBytes(Paths.get(helper)), StandardCharsets.UTF_8); + assertTrue(helper, source.contains("3f1100e6f75b1fb949cc883be7288aa30789876d")); + assertTrue(helper, source.contains("1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4")); + assertFalse(helper, source.contains("2116a35a40dd150d79e7dfdcdc891637793178b7")); + assertFalse(helper, source.contains("F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A")); + } for (String workflow : new String[] {"ci.yml", "codeql-analysis.yml"}) { String source = new String(Files.readAllBytes(Paths.get(".github/workflows", workflow)), StandardCharsets.UTF_8); int policy = source.indexOf("git config --global core.autocrlf false"); diff --git a/tools/verification/Verify-ElectricEcj.ps1 b/tools/verification/Verify-ElectricEcj.ps1 index 2eccdac..ff2582d 100644 --- a/tools/verification/Verify-ElectricEcj.ps1 +++ b/tools/verification/Verify-ElectricEcj.ps1 @@ -61,15 +61,15 @@ function Invoke-Ecj([string]$Name, [string[]]$Sources, [string[]]$Libraries) { } $report = [ordered]@{ status = 'RUNNING'; project = $ProjectRoot; evidence = $Evidence - scope = 'Electric D only; fresh ECJ main/test/helper outputs and worldless Java 8 JUnit; no Gradle or Minecraft launch' + scope = 'Pinned Electric 1.16.5 candidate; fresh ECJ main/test/helper outputs and worldless Java 8 JUnit; no Gradle or Minecraft launch' compiler = $null; toolchains = $null; libraries = @(); sources = @(); gradleInventory = @() compilations = [ordered]@{}; junit = $null } try { $properties = ConvertFrom-StringData -StringData (Get-Content -LiteralPath (Join-Path $ProjectRoot 'gradle.properties') -Raw) if ($properties.mod_id -ne 'electricadvantage' -or $properties.mod_version -ne '2.2.8.116051' -or - $properties.poweradvantage_source_ref -ne '2116a35a40dd150d79e7dfdcdc891637793178b7' -or - $properties.poweradvantage_deobf_sha256 -ne 'F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A') { - throw 'This verifier is pinned to the Electric 1.16.5 bootstrap-D candidate' + $properties.poweradvantage_source_ref -ne '3f1100e6f75b1fb949cc883be7288aa30789876d' -or + $properties.poweradvantage_deobf_sha256 -ne '1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4') { + throw 'This verifier requires the pinned Electric 1.16.5 candidate' } $report.compiler = Get-Pin $Compiler if ($report.compiler.sha256 -ne 'D0D43F8E2D7003E5EFED612E2CBB5F01870043397D8F1BBE536FD9128F4FCBF7') { throw 'ECJ compiler pin mismatch' } @@ -114,7 +114,7 @@ try { $expected += [int]$inventory.testsuite.tests $report.gradleInventory += Get-Pin $xml.FullName } - if ($classes.Count -ne 17 -or $expected -ne 47 -or $sources.test.Count -ne 17 -or $sources.main.Count -ne 85) { throw 'Unexpected Electric D source/test inventory' } + if ($classes.Count -ne 17 -or $expected -ne 47 -or $sources.test.Count -ne 17 -or $sources.main.Count -ne 85) { throw 'Unexpected Electric 1.16.5 source/test inventory' } $main = Invoke-Ecj 'main' $sources.main $mainLibraries $test = Invoke-Ecj 'test' $sources.test (@($main) + $testLibraries) $helperSource = Join-Path $PSScriptRoot 'AuditedJUnit.java' diff --git a/tools/verify-native-port.js b/tools/verify-native-port.js index edb4951..d92f0da 100644 --- a/tools/verify-native-port.js +++ b/tools/verify-native-port.js @@ -29,8 +29,8 @@ check('Exact native target metadata', () => { for (const pair of ['minecraft_version=1.16.5', 'forge_version=36.2.34', 'mapping_channel=official', 'mapping_version=1.16.5', 'mcp_version=20210115.111550', 'mod_version=2.2.8.116051', 'poweradvantage_version=2.4.7.116051', - 'poweradvantage_source_ref=2116a35a40dd150d79e7dfdcdc891637793178b7', - 'poweradvantage_deobf_sha256=F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A', + 'poweradvantage_source_ref=3f1100e6f75b1fb949cc883be7288aa30789876d', + 'poweradvantage_deobf_sha256=1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4', 'basemetals_version=3.1.1.116051', 'orespawn_version=4.1.0.116051', 'java_version=8', 'gradle_java_version=17']) { assert(properties.split(/\r?\n/).includes(pair), pair); From 5e24def88fd297dab38562cd5bccca9e894f4791 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 19:59:46 +0000 Subject: [PATCH 07/12] Clarify the local build instructions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 011d91b..6359abb 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ publication. Do not bypass the release audits or substitute a preliminary jar. Use immutable copies for verification, not a sibling's output that another build may replace. CI rejects pins that differ from this audited candidate. -With an authorized build slot, pass the immutable input paths and run: +With the pinned dependency jars available, pass their paths and run: ```text gradlew.bat classes test deobfJar -PpowerAdvantageDeobfJar= -PbaseMetalsDeobfJar= -PoreSpawnDeobfJar= From e8ad928d0311aebd10f64d10767bf8472e11095e Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 20:00:52 +0000 Subject: [PATCH 08/12] Use a versioned name for Eclipse test reports --- tools/verification/AuditedJUnit.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/verification/AuditedJUnit.java b/tools/verification/AuditedJUnit.java index 765a37d..a544297 100644 --- a/tools/verification/AuditedJUnit.java +++ b/tools/verification/AuditedJUnit.java @@ -30,7 +30,7 @@ public static void main(String[] args) throws Exception { XMLStreamWriter xml = XMLOutputFactory.newFactory().createXMLStreamWriter(output, "UTF-8"); xml.writeStartDocument("UTF-8", "1.0"); xml.writeStartElement("testsuite"); - xml.writeAttribute("name", "ElectricAdvantage-bootstrap-D-ECJ"); + xml.writeAttribute("name", "ElectricAdvantage-1.16.5-ECJ"); xml.writeAttribute("tests", Integer.toString(result.getRunCount())); xml.writeAttribute("failures", Integer.toString(result.getFailureCount())); xml.writeAttribute("ignored", Integer.toString(result.getIgnoreCount())); From 9a8fdf53a111499f2ebc969ac24a6f3e1017c18e Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 20:25:03 +0000 Subject: [PATCH 09/12] Build against the complete Forge attribute migration repair --- .github/workflows/ci.yml | 4 ++-- .github/workflows/codeql-analysis.yml | 4 ++-- CHANGELOG.txt | 2 +- README.md | 4 ++-- build.gradle | 4 ++-- docs/NATIVE116.md | 6 +++--- gradle.properties | 4 ++-- .../resources/BuildWorkflowContractTest.java | 8 ++++---- tools/verification/Verify-ElectricEcj.ps1 | 4 ++-- tools/verify-native-port.js | 4 ++-- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c1a4a23..3275320 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: set -euo pipefail power_ref="$(sed -n 's/^poweradvantage_source_ref=//p' gradle.properties | tr -d '\r')" power_sha="$(sed -n 's/^poweradvantage_deobf_sha256=//p' gradle.properties | tr -d '\r')" - if [[ "$power_ref" != "3f1100e6f75b1fb949cc883be7288aa30789876d" || "$power_sha" != "1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4" ]]; then + if [[ "$power_ref" != "bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7" || "$power_sha" != "2FB923944A456B4F26AB2F9212C646469CE3F49BFD4DAE894C15559B48908386" ]]; then echo "PowerAdvantage 1.16.5 source/deobf pin differs from the audited candidate" >&2 exit 1 fi @@ -53,7 +53,7 @@ jobs: with: repository: MinecraftModDevelopmentMods/PowerAdvantage # Local-only Power source; publish upstream before hosted builds. - ref: 3f1100e6f75b1fb949cc883be7288aa30789876d + ref: bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7 path: .ci-dependencies/PowerAdvantage - name: Install pinned Java 25 Mavenizer runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 0a90a42..ac3e2db 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -31,7 +31,7 @@ jobs: set -euo pipefail power_ref="$(sed -n 's/^poweradvantage_source_ref=//p' gradle.properties | tr -d '\r')" power_sha="$(sed -n 's/^poweradvantage_deobf_sha256=//p' gradle.properties | tr -d '\r')" - if [[ "$power_ref" != "3f1100e6f75b1fb949cc883be7288aa30789876d" || "$power_sha" != "1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4" ]]; then + if [[ "$power_ref" != "bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7" || "$power_sha" != "2FB923944A456B4F26AB2F9212C646469CE3F49BFD4DAE894C15559B48908386" ]]; then echo "PowerAdvantage 1.16.5 source/deobf pin differs from the audited candidate" >&2 exit 1 fi @@ -53,7 +53,7 @@ jobs: with: repository: MinecraftModDevelopmentMods/PowerAdvantage # Local-only Power source; publish upstream before hosted builds. - ref: 3f1100e6f75b1fb949cc883be7288aa30789876d + ref: bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7 path: .ci-dependencies/PowerAdvantage - name: Install pinned Java 25 Mavenizer runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 332ef6e..46b0ffd 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -5,7 +5,7 @@ Electric Advantage 2.2.8.116051 (local port candidate) - Use native renderer buffers, state-aware tile persistence and world-only Power Advantage conduit callbacks. - Retain lithium/sulfur mining levels through native correct-tool checks and serialize recipe-condition registration with enqueueWork. - Preserve registry IDs, legacy aliases, NBT keys, balance constants, recipes, discoveries and asset bytes from the accepted 1.15 source. -- Pin the Power Advantage 2.4.7.116051 build with the legacy Forge attribute repair; retain fail-closed release audits and keep dependencies out of the jar. +- Pin Power Advantage's repair for old Forge swimming speed, name-tag distance, gravity and player reach; keep exact release audits and dependencies outside the jar. - Pass all 47 Java tests with both Gradle and the Eclipse compiler, along with release and Eclipse audits against the pinned dependencies. - Recheck connected-machine upgrades, recipes, mining, loot and full-restart operation through the shared Advantage Works rig; keep wider migration checks and manual acceptance separate. diff --git a/README.md b/README.md index 6359abb..c7fd9f9 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,12 @@ inference and downloads. Build inputs are separate, non-embedded deobfuscated jars: -- Power Advantage `2.4.7.116051`: source `3f1100e6f75b1fb949cc883be7288aa30789876d`. +- Power Advantage `2.4.7.116051`: source `bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7`. - Base Metals `3.1.1.116051`: source `995f6cc4dd2d5eecc628a42e5c43fa5390c24bca`. - OreSpawn `4.1.0.116051`: source `a113e5d767169189f0e35ade1e173a12d550b00e`. Exact checksums are recorded in `gradle.properties`. Power deobf SHA-256 is -`1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4`. +`2FB923944A456B4F26AB2F9212C646469CE3F49BFD4DAE894C15559B48908386`. Its source is local-only; hosted reproducibility is pending upstream source publication. Do not bypass the release audits or substitute a preliminary jar. Use immutable copies for verification, not a sibling's output that another diff --git a/build.gradle b/build.gradle index 60a7bac..85a70eb 100644 --- a/build.gradle +++ b/build.gradle @@ -377,8 +377,8 @@ tasks.register('verifyReleaseConfiguration') { } if (project.poweradvantage_version != '2.4.7.116051' || project.poweradvantage_source_repository != 'MinecraftModDevelopmentMods/PowerAdvantage' - || project.poweradvantage_source_ref != '3f1100e6f75b1fb949cc883be7288aa30789876d' - || project.poweradvantage_deobf_sha256 != '1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4') { + || project.poweradvantage_source_ref != 'bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7' + || project.poweradvantage_deobf_sha256 != '2FB923944A456B4F26AB2F9212C646469CE3F49BFD4DAE894C15559B48908386') { throw new GradleException('Unexpected PowerAdvantage compile dependency identity') } if (project.basemetals_version != '3.1.1.116051' diff --git a/docs/NATIVE116.md b/docs/NATIVE116.md index 54c824b..1cc3256 100644 --- a/docs/NATIVE116.md +++ b/docs/NATIVE116.md @@ -12,9 +12,9 @@ checks and manual acceptance. Only checks actually executed may be marked passed - Base deobf SHA-256: `A7B0C4F394DFAF4E11E0275B1A86CB1D47C7AF8E175759D9BB84F965C684466D`. - OreSpawn `4.1.0.116051`, source `a113e5d767169189f0e35ade1e173a12d550b00e`. - OreSpawn deobf SHA-256: `DCEE75480C9DD70EE58B218AAE799C5FAB0525DAF9A05455270F1570C24F7F8F`. -- Power source: `3f1100e6f75b1fb949cc883be7288aa30789876d` (local-only). -- Power deobf SHA-256: `1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4`. -- Power release SHA-256: `EB226ADC200BFB96278F1449CDB7C6941F289DB43330C8206369048378E931EB`. +- Power source: `bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7` (local-only). +- Power deobf SHA-256: `2FB923944A456B4F26AB2F9212C646469CE3F49BFD4DAE894C15559B48908386`. +- Power release SHA-256: `5BE5C05D9F78BAF730553B71D07D76BA923EA0A54ABCA53F4149386B27019E71`. - Electric source: `61cbe49e513d4063f47a762dc3095b2239c625c2`. - Electric release SHA-256: `A9B62DD737E42455FEE72BD2D855C9C5EDBF5A9C5EAD7B48C650C9073A35B129`. diff --git a/gradle.properties b/gradle.properties index 8126556..096cec9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,8 +38,8 @@ cf_versions=1.16.5 poweradvantage_version=2.4.7.116051 poweradvantage_source_repository=MinecraftModDevelopmentMods/PowerAdvantage # Exact local-only Power source and immutable development artifact; publish source before hosted builds. -poweradvantage_source_ref=3f1100e6f75b1fb949cc883be7288aa30789876d -poweradvantage_deobf_sha256=1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4 +poweradvantage_source_ref=bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7 +poweradvantage_deobf_sha256=2FB923944A456B4F26AB2F9212C646469CE3F49BFD4DAE894C15559B48908386 basemetals_version=3.1.1.116051 basemetals_source_commit=995f6cc4dd2d5eecc628a42e5c43fa5390c24bca diff --git a/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java index eedd0a9..ca10fab 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/resources/BuildWorkflowContractTest.java @@ -32,8 +32,8 @@ public class BuildWorkflowContractTest { @Test public void dependencyPolicyPrecedesEveryPinnedCheckout() throws Exception { for (String helper : new String[] {"tools/verify-native-port.js", "tools/verification/Verify-ElectricEcj.ps1"}) { String source = new String(Files.readAllBytes(Paths.get(helper)), StandardCharsets.UTF_8); - assertTrue(helper, source.contains("3f1100e6f75b1fb949cc883be7288aa30789876d")); - assertTrue(helper, source.contains("1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4")); + assertTrue(helper, source.contains("bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7")); + assertTrue(helper, source.contains("2FB923944A456B4F26AB2F9212C646469CE3F49BFD4DAE894C15559B48908386")); assertFalse(helper, source.contains("2116a35a40dd150d79e7dfdcdc891637793178b7")); assertFalse(helper, source.contains("F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A")); } @@ -47,8 +47,8 @@ public class BuildWorkflowContractTest { assertTrue(source.contains("ref: a113e5d767169189f0e35ade1e173a12d550b00e")); assertTrue(source.contains("ref: 995f6cc4dd2d5eecc628a42e5c43fa5390c24bca")); assertTrue(source.contains("BaseMetals-3.1.1.116051-deobf.jar")); - assertTrue(source.contains("ref: 3f1100e6f75b1fb949cc883be7288aa30789876d")); - assertTrue(source.contains("1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4")); + assertTrue(source.contains("ref: bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7")); + assertTrue(source.contains("2FB923944A456B4F26AB2F9212C646469CE3F49BFD4DAE894C15559B48908386")); assertFalse(source.contains("098d4625abc8a849bd1a11dcf697b3fee0cade7b")); assertFalse(source.contains("78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3")); assertFalse(source.contains("ce90c24c302d0ff3565db2db0c6c94a3b5f21f83")); diff --git a/tools/verification/Verify-ElectricEcj.ps1 b/tools/verification/Verify-ElectricEcj.ps1 index ff2582d..86c7e05 100644 --- a/tools/verification/Verify-ElectricEcj.ps1 +++ b/tools/verification/Verify-ElectricEcj.ps1 @@ -67,8 +67,8 @@ $report = [ordered]@{ status = 'RUNNING'; project = $ProjectRoot; evidence = $Ev try { $properties = ConvertFrom-StringData -StringData (Get-Content -LiteralPath (Join-Path $ProjectRoot 'gradle.properties') -Raw) if ($properties.mod_id -ne 'electricadvantage' -or $properties.mod_version -ne '2.2.8.116051' -or - $properties.poweradvantage_source_ref -ne '3f1100e6f75b1fb949cc883be7288aa30789876d' -or - $properties.poweradvantage_deobf_sha256 -ne '1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4') { + $properties.poweradvantage_source_ref -ne 'bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7' -or + $properties.poweradvantage_deobf_sha256 -ne '2FB923944A456B4F26AB2F9212C646469CE3F49BFD4DAE894C15559B48908386') { throw 'This verifier requires the pinned Electric 1.16.5 candidate' } $report.compiler = Get-Pin $Compiler diff --git a/tools/verify-native-port.js b/tools/verify-native-port.js index d92f0da..08ad1ba 100644 --- a/tools/verify-native-port.js +++ b/tools/verify-native-port.js @@ -29,8 +29,8 @@ check('Exact native target metadata', () => { for (const pair of ['minecraft_version=1.16.5', 'forge_version=36.2.34', 'mapping_channel=official', 'mapping_version=1.16.5', 'mcp_version=20210115.111550', 'mod_version=2.2.8.116051', 'poweradvantage_version=2.4.7.116051', - 'poweradvantage_source_ref=3f1100e6f75b1fb949cc883be7288aa30789876d', - 'poweradvantage_deobf_sha256=1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4', + 'poweradvantage_source_ref=bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7', + 'poweradvantage_deobf_sha256=2FB923944A456B4F26AB2F9212C646469CE3F49BFD4DAE894C15559B48908386', 'basemetals_version=3.1.1.116051', 'orespawn_version=4.1.0.116051', 'java_version=8', 'gradle_java_version=17']) { assert(properties.split(/\r?\n/).includes(pair), pair); From d5a5984ecc2e9d4dd2eb77dcf8ca01eea6035b7d Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 21:46:34 +0000 Subject: [PATCH 10/12] Record Electric Advantage's 1.16.5 shared runtime checks --- README.md | 5 +++-- docs/NATIVE116.md | 16 +++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index c7fd9f9..1e46b3d 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,9 @@ **Minecraft 1.16.5 port candidate, version 2.2.8.116051.** All 47 Java tests, release audits, Eclipse checks and independent Eclipse-compiler tests pass against the pinned Power Advantage build. Combined machine, recipe, mining and -connected-world upgrade checks also pass; wider migration checks are still being -completed. Manual acceptance is pending. This is not a published release. +connected-world upgrade checks also pass. Broader player/entity checks retain a +separately controlled vanilla wolf-health difference. Manual acceptance is +pending. This is not a published release. See [the native port checklist](docs/NATIVE116.md). The [shared test record](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.16.5/docs/1.16/CURRENT-QUALIFICATION.md) records the exact jars, completed checks and remaining limits. That page will be diff --git a/docs/NATIVE116.md b/docs/NATIVE116.md index 1cc3256..d689c65 100644 --- a/docs/NATIVE116.md +++ b/docs/NATIVE116.md @@ -15,7 +15,7 @@ checks and manual acceptance. Only checks actually executed may be marked passed - Power source: `bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7` (local-only). - Power deobf SHA-256: `2FB923944A456B4F26AB2F9212C646469CE3F49BFD4DAE894C15559B48908386`. - Power release SHA-256: `5BE5C05D9F78BAF730553B71D07D76BA923EA0A54ABCA53F4149386B27019E71`. -- Electric source: `61cbe49e513d4063f47a762dc3095b2239c625c2`. +- Electric tested production source: `9a8fdf53a111499f2ebc969ac24a6f3e1017c18e`. - Electric release SHA-256: `A9B62DD737E42455FEE72BD2D855C9C5EDBF5A9C5EAD7B48C650C9073A35B129`. Copy the final verified jars to immutable local input paths before building. @@ -33,9 +33,10 @@ the dependency repin changes no Electric class or resource. The current packaged jars pass combined Works, recipe modes and unlocks, survival mining and drops, extended drills, and connected-world operating -checks after upgrades. Current unloading and broader player/entity checks are -tracked in Power Advantage's `docs/1.16/CURRENT-QUALIFICATION.md`; incomplete -cases are not counted as passes. Manual rendering, controls, sounds, weapons, +checks after upgrades. The shared `docs/1.16/CURRENT-QUALIFICATION.md` records +unloading and broader player/entity checks, including the separately controlled +vanilla wolf-health difference. Incomplete cases are not counted as passes. +Manual rendering, controls, sounds, weapons, multiplayer and actual player login still need checking. The bootstrap notes below are historical receipts, not current readiness @@ -59,7 +60,8 @@ claims. Failed and interrupted runs remain recorded under their original names. - Rendering retains all geometry, UVs, winding normals, light/overlay values, timing, six drill directions, tracking settings and original test tolerances. - Condition registration uses common setup's `enqueueWork`. Native tag loading - and reload integration belong to Power and still need runtime proof. + and reload integration belong to Power and are covered by the shared recipe, + reload and restart checks. - Electric's tag resources contain no legacy `optional` arrays. Any future optional reference must use `values: [{"id": "...", "required": false}]`. @@ -147,8 +149,8 @@ strict registry/async-save ERROR gate on boot 16. Its raw audit and all source custody remain preserved under `evidence/native116_actor_d_20261027/` and the parent's test-rig. No strict identity, item or health oracle was relaxed. The F actor/storage attempt is retained as interrupted baseline-only evidence, -not final qualification. A new 108-boot matrix needs sealed G inputs and a new -runtime lease. Dedicated native114 actor-origin fixtures remain unqualified; a native115 +not final qualification. At that checkpoint, a new 108-boot matrix was planned +with sealed G inputs and a new runtime lease. Dedicated native114 actor-origin fixtures remain unqualified; a native115 actor extension needs explicit stopped-source custody, not an old destination PASS. At that historical checkpoint, runtime and acceptance work remained: From 4a7f85d45174ca3552763c38852fb319ce932578 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Fri, 30 Oct 2026 20:50:26 +0000 Subject: [PATCH 11/12] Fix Electric Advantage machine state and strengthen Minecraft 1.16.5 tests --- CHANGELOG.txt | 13 +- README.md | 19 +- docs/NATIVE116.md | 24 +- .../entities/HydroturbineEntity.java | 6 + .../mc/electricadvantage/gui/GUIHelper.java | 12 +- .../machines/ElectricGeneratorTileEntity.java | 19 +- .../machines/ElectricMachineTileEntity.java | 19 +- .../machines/ElectricPumpTileEntity.java | 24 +- .../machines/ElectricStillTileEntity.java | 15 +- .../GrowthChamberControllerTileEntity.java | 5 +- .../HydroelectricGeneratorTileEntity.java | 2 +- .../machines/LaserTurretTileEntity.java | 13 +- .../PhotovoltaicGeneratorTileEntity.java | 6 +- .../blocks/OreHarvestContractTest.java | 7 +- ...tricOperationalHydroturbineAnchorTest.java | 112 +++++++++ .../entities/HydroturbinePersistenceTest.java | 19 +- .../graphics/RendererBufferContractTest.java | 6 +- .../electricadvantage/gui/GUIHelperTest.java | 29 +++ .../ElectricOperationalNativeDefectsTest.java | 147 ++++++++++++ .../ElectricOperationalPumpPickupTest.java | 205 ++++++++++++++++ .../ElectricOperationalRedstoneCacheTest.java | 218 ++++++++++++++++++ ...ElectricOperationalSoundBroadcastTest.java | 128 ++++++++++ .../ElectricOperationalStillCapacityTest.java | 68 ++++++ tools/verification/Verify-ElectricEcj.ps1 | 10 +- 24 files changed, 1075 insertions(+), 51 deletions(-) create mode 100644 src/test/java/zone/moddev/mc/electricadvantage/entities/ElectricOperationalHydroturbineAnchorTest.java create mode 100644 src/test/java/zone/moddev/mc/electricadvantage/gui/GUIHelperTest.java create mode 100644 src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalNativeDefectsTest.java create mode 100644 src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalPumpPickupTest.java create mode 100644 src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalRedstoneCacheTest.java create mode 100644 src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalSoundBroadcastTest.java create mode 100644 src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalStillCapacityTest.java diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 46b0ffd..fc7cb5b 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,12 +1,23 @@ Electric Advantage 2.2.8.116051 (local port candidate) +- Check generator redstone before the first power pulse so a disabled solar panel cannot produce a startup burst. +- Sample machine redstone on first use after loading so the interlock applies before the first eight-tick cache refresh. +- Use native bucket pickup in electric pumps so waterlogged blocks survive draining and non-pickup blocks remain untouched. +- Keep hydroturbines anchored so flowing water cannot accumulate unused linear motion that native loading discards. +- Send machine and generator sounds to existing nearby players without querying chunks; skip players without connections. +- Limit growth-controller electricity requests to available input capacity and account for energy already stored. +- Sample solar light above the solid panel and keep turret beams from colliding with their own mounting post. +- Preserve still input and electricity when the output tank cannot hold a complete distillation result. +- Keep progress and fluid indicators inside their GUI frames. +- Show the hydroelectric generator's output on the same 0-to-1 scale as the other generators, without changing its energy production. +- Fix restricted-JDK access errors in Eclipse test fixtures and include those restrictions in the independent compiler check; gameplay code is unchanged. - Target Minecraft 1.16.5, Forge 36.2.34, official 1.16.5 mappings and MCP 20210115.111550. - Retain Java 8 runtime/bytecode, Java 17 Gradle, Java 25 Mavenizer, ForgeGradle 7.0.34 and Gradle 9.6.1. - Use native renderer buffers, state-aware tile persistence and world-only Power Advantage conduit callbacks. - Retain lithium/sulfur mining levels through native correct-tool checks and serialize recipe-condition registration with enqueueWork. - Preserve registry IDs, legacy aliases, NBT keys, balance constants, recipes, discoveries and asset bytes from the accepted 1.15 source. - Pin Power Advantage's repair for old Forge swimming speed, name-tag distance, gravity and player reach; keep exact release audits and dependencies outside the jar. -- Pass all 47 Java tests with both Gradle and the Eclipse compiler, along with release and Eclipse audits against the pinned dependencies. +- Check the current Java tests with both Gradle and the Eclipse compiler, alongside release and Eclipse audits against the pinned dependencies. - Recheck connected-machine upgrades, recipes, mining, loot and full-restart operation through the shared Advantage Works rig; keep wider migration checks and manual acceptance separate. Electric Advantage 2.2.7.115021 diff --git a/README.md b/README.md index 1e46b3d..e2a0c24 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # Electric Advantage -**Minecraft 1.16.5 port candidate, version 2.2.8.116051.** All 47 Java tests, -release audits, Eclipse checks and independent Eclipse-compiler tests pass -against the pinned Power Advantage build. Combined machine, recipe, mining and -connected-world upgrade checks also pass. Broader player/entity checks retain a -separately controlled vanilla wolf-health difference. Manual acceptance is -pending. This is not a published release. +**Minecraft 1.16.5 port candidate, version 2.2.8.116051.** +The follow-up checks measure finite machine jobs, energy and fluid conservation, +blocked routes, real turret hits and full-process restarts. Rendered GUI checks +require the correct labels as well as correctly placed controls. The shared +record below identifies the current jars and each completed run; earlier +results are retained separately rather than counted again. Broader player/entity +checks retain a separately controlled vanilla wolf-health difference. +Manual acceptance is pending. This is not a published release. See [the native port checklist](docs/NATIVE116.md). The [shared test record](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.16.5/docs/1.16/CURRENT-QUALIFICATION.md) records the exact jars, completed checks and remaining limits. That page will be @@ -106,3 +108,8 @@ No 1.16 publication is included before manual acceptance. Always back up a whole world before upgrading and test only disposable copies. Keep migration backups and failed evidence. Bounded Advantage results never qualify unrelated mods or an arbitrary existing modpack. + +The shared [machine operating checks](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.16.5/docs/1.16/OPERATING-TESTS.md) +exercise finite processing, fabrication, growth, pumping, lighting, generation, +battery and turret jobs. They check real output, damage and resource use, with +blocked and starved controls and complete server restarts. diff --git a/docs/NATIVE116.md b/docs/NATIVE116.md index d689c65..162ee3f 100644 --- a/docs/NATIVE116.md +++ b/docs/NATIVE116.md @@ -3,7 +3,24 @@ This checklist separates source changes, deterministic tests, packaged runtime checks and manual acceptance. Only checks actually executed may be marked passed. -## Inputs +## Current Follow-Up + +The local machine corrections pass 84 Java tests with Gradle and the Eclipse +compiler. The shared [qualification record](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.16.5/docs/1.16/CURRENT-QUALIFICATION.md) +identifies the new jars and their operating, cold-restart and negative-control +checks. Neither the frozen hashes nor the earlier GUI results below qualify a +different build. Manual acceptance and publication remain separate. + +## Earlier GUI Follow-Up + +The local display correction bounds progress/fluid indicators and normalizes the +hydroelectric GUI reading without changing generation. All 51 Java tests pass +with Gradle and a fresh Eclipse compiler. All 15 registered Electric screens +also pass the combined native layout, inventory-hover and item-tooltip checks. +The shared Power test record keeps these new jar hashes separate from the +earlier frozen machine and migration qualification. + +## Frozen Port Inputs - Electric source baseline: `74aa1cee1ddec821ebcd12b9f8b0515b7aec61d9`. - Electric candidate: `2.2.8.116051`; Power candidate: `2.4.7.116051`. @@ -42,6 +59,11 @@ multiplayer and actual player login still need checking. The bootstrap notes below are historical receipts, not current readiness claims. Failed and interrupted runs remain recorded under their original names. +The 28 October Eclipse correction removes direct `Unsafe` imports from test +fixtures. The independent compiler now applies Java 8 JRE access rules and +treats restricted references as errors. No project-wide warning suppression or +gameplay change is required. + ## Source Contracts - All recipe, advancement, tag, loot, model, texture and translation resources diff --git a/src/main/java/zone/moddev/mc/electricadvantage/entities/HydroturbineEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/entities/HydroturbineEntity.java index 03362a9..60392e9 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/entities/HydroturbineEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/entities/HydroturbineEntity.java @@ -54,6 +54,12 @@ public IPacket getAddEntityPacket() { return NetworkHooks.getEntitySpawningPacket(this); } + @Override + public boolean isPushedByFluid() { + // This is anchored to its generator; flow drives rotation, not linear movement. + return false; + } + @Override public void tick(){ super.tick(); diff --git a/src/main/java/zone/moddev/mc/electricadvantage/gui/GUIHelper.java b/src/main/java/zone/moddev/mc/electricadvantage/gui/GUIHelper.java index 81a9761..41a7ab0 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/gui/GUIHelper.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/gui/GUIHelper.java @@ -31,17 +31,23 @@ public static void drawIndicatorLight(boolean on,GUIContainer gc, int xOffset, i } public static void drawProgressBar(int x, int y, float progress, GUIContainer gc){ - int n = (int)(8 * (progress + 0.0625f) ); - if(n <= 0) return; - int w = 1 + (n * LED_BAR_W8); + int w = progressBarWidth(progress); + if(w == 0) return; gc.blit(x, y, LED_BAR_X, LED_BAR_Y, w, LED_BAR_H); } + + static int progressBarWidth(float progress) { + progress = Float.isFinite(progress) ? Math.max(0F, Math.min(1F, progress)) : 0F; + int n = (int)(8 * (progress + 0.0625f)); + return n <= 0 ? 0 : 1 + n * LED_BAR_W8; + } public static void drawFluidBar(FluidStack fs, float barHeight, int xPos, int yPos, GUIContainer guiContainer, int x, int y, float z, ResourceLocation displayImage){ + barHeight = Float.isFinite(barHeight) ? Math.max(0F, Math.min(1F, barHeight)) : 0F; final int w = 16; final int barSlotHeight = 60; final int h = (int)(barSlotHeight * barHeight); diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricGeneratorTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricGeneratorTileEntity.java index fa5b34f..6e55ebb 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricGeneratorTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricGeneratorTileEntity.java @@ -3,6 +3,7 @@ import zone.moddev.mc.electricadvantage.init.Power; import cyano.poweradvantage.api.ConduitType; import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; @@ -18,7 +19,6 @@ import zone.moddev.mc.electricadvantage.ElectricAdvantage; import java.util.Arrays; -import java.util.List; public abstract class ElectricGeneratorTileEntity extends cyano.poweradvantage.api.simple.TileEntitySimplePowerMachine { @@ -46,12 +46,14 @@ public ElectricGeneratorTileEntity(TileEntityType tileType, String name,int n private boolean redstone = false; + private boolean redstoneInitialized = false; private float oldEnergy = 0f; @Override public void powerUpdate(){ super.powerUpdate(); redstone = getLevel().hasNeighborSignal(getBlockPos()); + redstoneInitialized = true; if(oldEnergy != this.getEnergy(Power.ELECTRIC_POWER)){ this.sync(); @@ -59,6 +61,11 @@ public void powerUpdate(){ } protected boolean hasRedstoneSignal(){ + // Generators can check the interlock before their first power-update refresh. + if(!redstoneInitialized && getLevel() != null && !getLevel().isClientSide){ + redstone = getLevel().hasNeighborSignal(getBlockPos()); + redstoneInitialized = true; + } return redstone; } @@ -74,10 +81,14 @@ protected void setActive(boolean active){ protected void playSoundEffect(double x, double y, double z, SoundEvent sound, float volume, float pitch){ if(getLevel().isClientSide) return; final double range = 16; - List players = getLevel().getEntitiesOfClass(ServerPlayerEntity.class, new AxisAlignedBB( + AxisAlignedBB bounds = new AxisAlignedBB( x - range, y - range, z - range, - x + range, y + range, z + range)); - for(ServerPlayerEntity player : players){ + x + range, y + range, z + range); + // A world-wide entity query can load chunks just to broadcast a sound. + for(PlayerEntity candidate : getLevel().players()){ + if(!(candidate instanceof ServerPlayerEntity)) continue; + ServerPlayerEntity player = (ServerPlayerEntity)candidate; + if(player.connection == null || player.isSpectator() || !player.getBoundingBox().intersects(bounds)) continue; player.connection.send(new SPlaySoundPacket(sound.getRegistryName(), SoundCategory.BLOCKS, new net.minecraft.util.math.vector.Vector3d(x, y, z), volume, pitch)); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricMachineTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricMachineTileEntity.java index bff7661..0f9feb7 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricMachineTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricMachineTileEntity.java @@ -3,6 +3,7 @@ import zone.moddev.mc.electricadvantage.init.Power; import cyano.poweradvantage.api.ConduitType; import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.Inventory; import net.minecraft.item.ItemStack; @@ -22,7 +23,6 @@ import zone.moddev.mc.electricadvantage.ElectricAdvantage; import java.util.Arrays; -import java.util.List; public abstract class ElectricMachineTileEntity extends cyano.poweradvantage.api.simple.TileEntitySimplePowerMachine{ @@ -71,6 +71,7 @@ public ElectricMachineTileEntity(TileEntityType tileType, String name,int num } private boolean redstone = false; + private boolean redstoneInitialized = false; private float oldEnergy = 0f; private int[] syncArrayOld = null; private int[] syncArrayNew = null; @@ -79,6 +80,7 @@ public void powerUpdate(){ super.powerUpdate(); redstone = getLevel().hasNeighborSignal(getBlockPos()); + redstoneInitialized = true; this.setPowerState(this.isPowered()); @@ -99,6 +101,11 @@ public void powerUpdate(){ protected boolean hasRedstoneSignal(){ + // tickUpdate runs before the first scheduled powerUpdate after loading. + if(!redstoneInitialized && getLevel() != null && !getLevel().isClientSide){ + redstone = getLevel().hasNeighborSignal(getBlockPos()); + redstoneInitialized = true; + } return redstone; } @@ -343,10 +350,14 @@ public ItemStack insertItemToInputSlots(ItemStack itemStack){ protected void playSoundEffect(double x, double y, double z, SoundEvent sound, float volume, float pitch){ if(getLevel().isClientSide) return; final double range = 16; - List players = getLevel().getEntitiesOfClass(ServerPlayerEntity.class, new AxisAlignedBB( + AxisAlignedBB bounds = new AxisAlignedBB( x - range, y - range, z - range, - x + range, y + range, z + range)); - for(ServerPlayerEntity player : players){ + x + range, y + range, z + range); + // A world-wide entity query can load chunks just to broadcast a sound. + for(PlayerEntity candidate : getLevel().players()){ + if(!(candidate instanceof ServerPlayerEntity)) continue; + ServerPlayerEntity player = (ServerPlayerEntity)candidate; + if(player.connection == null || player.isSpectator() || !player.getBoundingBox().intersects(bounds)) continue; player.connection.send(new SPlaySoundPacket(sound.getRegistryName(), SoundCategory.BLOCKS, new net.minecraft.util.math.vector.Vector3d(x, y, z), volume, pitch)); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricPumpTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricPumpTileEntity.java index 8e5cc33..4e474ce 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricPumpTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricPumpTileEntity.java @@ -9,6 +9,7 @@ import zone.moddev.mc.poweradvantage.init.Fluids; import zone.moddev.mc.poweradvantage.util.FluidIdHelper; import net.minecraft.block.BlockState; +import net.minecraft.block.IBucketPickupHandler; import net.minecraft.util.SoundEvents; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; @@ -82,12 +83,14 @@ public void tickUpdate(boolean isServerWorld) { float cost = ENERGY_COST_PUMP+ENERGY_COST_VERTICAL*(getBlockPos().getY()-fluidSource.getY()); // Found a fluid to suck-up! BlockState blockstate = w.getBlockState(fluidSource); - Fluid f = getFluid(blockstate); - if(f != null && getEnergy() >= cost){ - this.getTank().fill(new FluidStack(f, FluidTank.BUCKET_VOLUME), true); - this.subtractEnergy(cost, Power.ELECTRIC_POWER); - w.setBlock(fluidSource, net.minecraft.block.Blocks.AIR.defaultBlockState(), 3); - success = true; + if(blockstate.getBlock() instanceof IBucketPickupHandler && getEnergy() >= cost){ + // Native pickup drains waterlogging without deleting the containing block. + Fluid f = ((IBucketPickupHandler)blockstate.getBlock()).takeLiquid(w, fluidSource, blockstate); + if(f != null && f != net.minecraft.fluid.Fluids.EMPTY){ + this.getTank().fill(new FluidStack(f, FluidTank.BUCKET_VOLUME), true); + this.subtractEnergy(cost, Power.ELECTRIC_POWER); + success = true; + } } } timeUntilNextPump = PUMP_INTERVAL; @@ -129,12 +132,6 @@ protected boolean isValidInputItem(ItemStack item) { } - private Fluid getFluid(BlockState blockstate) { - return blockstate.getFluidState().isEmpty() ? null : blockstate.getFluidState().getType(); - } - - - private BlockPos scan(Set searchSpace, BlockPos coord, int limit) { if(isFluidBlock(coord) == false) return null; do{ @@ -161,7 +158,8 @@ private BlockPos scan(Set searchSpace, BlockPos coord, int limit) { } private boolean isSourceBlock( BlockPos coord){ - return getLevel().getFluidState(coord).isSource(); + BlockState state = getLevel().getBlockState(coord); + return state.getBlock() instanceof IBucketPickupHandler && state.getFluidState().isSource(); } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricStillTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricStillTileEntity.java index 9d19cf5..c7d4e3e 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricStillTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/ElectricStillTileEntity.java @@ -48,7 +48,8 @@ public void tickUpdate(boolean isServerWorld) { if(!this.hasRedstoneSignal()){ if(getInputTank().getFluidAmount() > 0 && getEnergy() >= electricityPerDistill - && canDistill(getInputTank().getFluid())){ + && canDistill(getInputTank().getFluid()) + && hasSpaceForDistillation()){ distill(); if(!wasActive){ this.setActiveState(true); @@ -93,6 +94,18 @@ private boolean canDistill(FluidStack fs) { } } + private boolean hasSpaceForDistillation() { + DistillationRecipe recipe = DistillationRecipeRegistry.getInstance() + .getDistillationRecipeForFluid(getInputTank().getFluid().getFluid()); + return hasSpaceForDistillation(recipe); + } + + private boolean hasSpaceForDistillation(DistillationRecipe recipe) { + // Preview on a copy: applyRecipe consumes its input before the output is inserted. + FluidStack output = recipe.applyRecipe(getInputTank().getFluid().copy(), speed); + return output != null && getOutputTank().fill(output, false) == output.amount; + } + private void distill(){ DistillationRecipe recipe = DistillationRecipeRegistry.getInstance() .getDistillationRecipeForFluid(getInputTank().getFluid().getFluid()); diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberControllerTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberControllerTileEntity.java index 7822660..0808c80 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberControllerTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/GrowthChamberControllerTileEntity.java @@ -315,7 +315,10 @@ public PowerRequest getPowerRequest(ConduitType offer) { float powerWanted = (this.getEnergyCapacity(Power.GROWTHCHAMBER_POWER) - this.getEnergy(Power.GROWTHCHAMBER_POWER)); powerWanted = Math.min(powerWanted, soil / SOIL_PER_UNIT); powerWanted = Math.min(powerWanted, tank.getFluidAmount() / WATER_PER_UNIT); - return new PowerRequest(PowerRequest.MEDIUM_PRIORITY,ELECTRICITY_PER_UNIT * powerWanted,this); + float stored = getEnergy(Power.ELECTRIC_POWER); + float room = getEnergyCapacity(Power.ELECTRIC_POWER) - stored; + float electricityWanted = Math.max(0, Math.min(room, ELECTRICITY_PER_UNIT * powerWanted - stored)); + return new PowerRequest(PowerRequest.MEDIUM_PRIORITY,electricityWanted,this); } else { return PowerRequest.REQUEST_NOTHING; } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/HydroelectricGeneratorTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/HydroelectricGeneratorTileEntity.java index 051e1c4..9c56787 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/HydroelectricGeneratorTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/HydroelectricGeneratorTileEntity.java @@ -53,7 +53,7 @@ private void initialize() { @Override public float getPowerOutput() { if(this.isActive()){ - return 15; + return 1F; } else { return 0; } diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/LaserTurretTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/LaserTurretTileEntity.java index 4a6c19f..14a6ec1 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/LaserTurretTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/LaserTurretTileEntity.java @@ -20,6 +20,9 @@ import net.minecraft.util.SoundEvent; import net.minecraft.util.math.*; import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.util.math.shapes.VoxelShapes; +import net.minecraft.world.IBlockReader; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -295,9 +298,15 @@ private Vector3d calculateLaserTerminus(){ return followRayToSolidBlock(getOpticPosition(),dir,ATTACK_RANGE); } private Vector3d followRayToSolidBlock(Vector3d origin, Vector3d dir, double maxRange){ - Vector3d max = origin.add(dir).add(maxRange * dir.x, maxRange * dir.y, maxRange * dir.z); + Vector3d max = origin.add(maxRange * dir.x, maxRange * dir.y, maxRange * dir.z); BlockRayTraceResult impact = getLevel().clip(new RayTraceContext(origin, max, - RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.SOURCE_ONLY, null)); + RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.SOURCE_ONLY, null) { + @Override public VoxelShape getBlockShape(BlockState state, IBlockReader world, BlockPos pos) { + // The optic is inside our collision post; ignore only this block, not nearby cover. + return pos.equals(LaserTurretTileEntity.this.getBlockPos()) ? VoxelShapes.empty() + : super.getBlockShape(state, world, pos); + } + }); if(impact.getType() == RayTraceResult.Type.BLOCK){ return impact.getLocation(); } else { diff --git a/src/main/java/zone/moddev/mc/electricadvantage/machines/PhotovoltaicGeneratorTileEntity.java b/src/main/java/zone/moddev/mc/electricadvantage/machines/PhotovoltaicGeneratorTileEntity.java index c9125ea..fbcad36 100644 --- a/src/main/java/zone/moddev/mc/electricadvantage/machines/PhotovoltaicGeneratorTileEntity.java +++ b/src/main/java/zone/moddev/mc/electricadvantage/machines/PhotovoltaicGeneratorTileEntity.java @@ -92,8 +92,10 @@ public void powerUpdate(){ } public static float getLightIntensityAt(BlockPos pos, World w){ + // The panel is solid; sample incident light above its top surface, not inside it. + BlockPos lightPos = pos.above(); float light; - if(w.canSeeSky(pos) && w.dimensionType().hasSkyLight()){ + if(w.canSeeSky(lightPos) && w.dimensionType().hasSkyLight()){ // outdoor light imposes no penalty light = MathHelper.sin((float)w.getDayTime() * 2.61799E-4f); // (worldTime * pi / 12000); // handle weather @@ -103,7 +105,7 @@ public static float getLightIntensityAt(BlockPos pos, World w){ light *= 0.35f; } } else { - float blockLight = w.getMaxLocalRawBrightness(pos) * 6.66666E-2f; // block light / 15 + float blockLight = w.getMaxLocalRawBrightness(lightPos) * 6.66666E-2f; // block light / 15 light = BLOCKLIGHT_FACTOR * blockLight; } return light; diff --git a/src/test/java/zone/moddev/mc/electricadvantage/blocks/OreHarvestContractTest.java b/src/test/java/zone/moddev/mc/electricadvantage/blocks/OreHarvestContractTest.java index 28c6f5c..309a58a 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/blocks/OreHarvestContractTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/blocks/OreHarvestContractTest.java @@ -13,7 +13,6 @@ import net.minecraftforge.common.ToolType; import org.junit.BeforeClass; import org.junit.Test; -import sun.misc.Unsafe; import static org.junit.Assert.*; public class OreHarvestContractTest { @@ -43,9 +42,11 @@ public class OreHarvestContractTest { } private static boolean canHarvest(BlockState state, ItemStack held) throws Exception { - Field field = Unsafe.class.getDeclaredField("theUnsafe"); + Class allocator = Class.forName("sun.misc.Unsafe"); + Field field = allocator.getDeclaredField("theUnsafe"); field.setAccessible(true); - HarvestPlayer player = (HarvestPlayer) ((Unsafe) field.get(null)).allocateInstance(HarvestPlayer.class); + HarvestPlayer player = (HarvestPlayer) allocator.getMethod("allocateInstance", Class.class) + .invoke(field.get(null), HarvestPlayer.class); player.held = held; return ForgeHooks.canHarvestBlock(state, player, EmptyBlockReader.INSTANCE, BlockPos.ZERO); } diff --git a/src/test/java/zone/moddev/mc/electricadvantage/entities/ElectricOperationalHydroturbineAnchorTest.java b/src/test/java/zone/moddev/mc/electricadvantage/entities/ElectricOperationalHydroturbineAnchorTest.java new file mode 100644 index 0000000..d68016c --- /dev/null +++ b/src/test/java/zone/moddev/mc/electricadvantage/entities/ElectricOperationalHydroturbineAnchorTest.java @@ -0,0 +1,112 @@ +package zone.moddev.mc.electricadvantage.entities; + +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.Random; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityClassification; +import net.minecraft.entity.EntityType; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.DoubleNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.network.IPacket; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.registry.Bootstrap; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class ElectricOperationalHydroturbineAnchorTest { + @BeforeClass public static void bootstrap() { Bootstrap.bootStrap(); } + + @Test public void nativeEntityLoadStillClampsOverspeedMotionAndPreservesItsBoundary() throws Exception { + ControlEntity control = new ControlEntity(controlType(), world()); + CompoundNBT tag = control.saveWithoutId(new CompoundNBT()); + tag.put("Motion", motion(16.226, -10.001, 10)); + control.load(tag); + assertEquals(new Vector3d(0, 0, 10), control.getDeltaMovement()); + assertTrue(control.isPushedByFluid()); + } + + @Test public void turbineRejectsLinearWaterPushingWithoutChangingRotationRate() throws Exception { + HydroturbineEntity turbine = new HydroturbineEntity(turbineType(), world()); + assertFalse(turbine.isPushedByFluid()); + assertEquals(Vector3d.ZERO, turbine.getDeltaMovement()); + assertEquals(30, HydroturbineEntity.DEGREES_PER_TICK, 0); + } + + @Test public void legacyMotionInsideTheNativeLimitIsNotArbitrarilyCleared() throws Exception { + HydroturbineEntity turbine = new HydroturbineEntity(turbineType(), world()); + CompoundNBT saved = turbine.saveWithoutId(new CompoundNBT()); + saved.put("Motion", motion(5.5, -2, 0)); + turbine.load(saved); + assertEquals(new Vector3d(5.5, -2, 0), turbine.getDeltaMovement()); + assertFalse(turbine.isPushedByFluid()); + } + + @Test public void anchoredTurbineSurvivesNativeSaveLoadWithItsParentAndIdentity() throws Exception { + EntityType type = turbineType(); + World world = world(); + HydroturbineEntity original = new HydroturbineEntity(type, world); + original.setPos(56856.5, 81, 50008.5); + CompoundNBT saved = original.saveWithoutId(new CompoundNBT()); + int[] parent = {56856, 82, 50008}; + saved.putIntArray("parentPos", parent); + for (int pass = 0; pass < 3; pass++) { + HydroturbineEntity loaded = new HydroturbineEntity(type, world); + loaded.load(saved); + CompoundNBT next = loaded.saveWithoutId(new CompoundNBT()); + assertEquals(saved.getUUID("UUID"), next.getUUID("UUID")); + assertEquals(saved.getList("Pos", 6), next.getList("Pos", 6)); + assertEquals(motion(0, 0, 0), next.getList("Motion", 6)); + assertArrayEquals(parent, next.getIntArray("parentPos")); + assertFalse(loaded.isPushedByFluid()); + saved = next; + } + } + + private static ListNBT motion(double x, double y, double z) { + ListNBT list = new ListNBT(); + list.add(DoubleNBT.valueOf(x)); list.add(DoubleNBT.valueOf(y)); list.add(DoubleNBT.valueOf(z)); + return list; + } + + private static EntityType turbineType() { + return EntityType.Builder.of(HydroturbineEntity::new, EntityClassification.MISC) + .sized(1, 1).build("electricadvantage:test_anchored_turbine"); + } + + private static EntityType controlType() { + return EntityType.Builder.of(ControlEntity::new, EntityClassification.MISC) + .sized(1, 1).build("electricadvantage:test_native_motion_control"); + } + + private static World world() throws Exception { + Class allocator = Class.forName("sun.misc.Unsafe"); + Field field = allocator.getDeclaredField("theUnsafe"); + field.setAccessible(true); + World world = (World)allocator.getMethod("allocateInstance", Class.class) + .invoke(field.get(null), NoTickWorld.class); + Field random = World.class.getField("random"); + random.setAccessible(true); + random.set(world, new Random(0)); + return world; + } + + private static final class NoTickWorld extends ServerWorld { + private NoTickWorld() { + super(null, null, null, null, null, null, null, null, false, 0L, Collections.emptyList(), false); + } + } + + private static final class ControlEntity extends Entity { + ControlEntity(EntityType type, World world) { super(type, world); } + @Override protected void defineSynchedData() {} + @Override protected void readAdditionalSaveData(CompoundNBT tag) {} + @Override protected void addAdditionalSaveData(CompoundNBT tag) {} + @Override public IPacket getAddEntityPacket() { return null; } + } +} diff --git a/src/test/java/zone/moddev/mc/electricadvantage/entities/HydroturbinePersistenceTest.java b/src/test/java/zone/moddev/mc/electricadvantage/entities/HydroturbinePersistenceTest.java index 389c5cb..c338fa2 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/entities/HydroturbinePersistenceTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/entities/HydroturbinePersistenceTest.java @@ -5,11 +5,22 @@ import net.minecraft.util.math.BlockPos; import zone.moddev.mc.electricadvantage.machines.HydroelectricGeneratorTileEntity; import org.junit.Test; -import sun.misc.Unsafe; import static org.junit.Assert.*; public class HydroturbinePersistenceTest { + @Test public void generatorGuiOutputIsNormalizedWithoutChangingGenerationRate() { + HydroelectricGeneratorTileEntity active = new HydroelectricGeneratorTileEntity() { + @Override public boolean isActive() { return true; } + }; + HydroelectricGeneratorTileEntity inactive = new HydroelectricGeneratorTileEntity() { + @Override public boolean isActive() { return false; } + }; + assertEquals(1F, active.getPowerOutput(), 0F); + assertEquals(0F, inactive.getPowerOutput(), 0F); + assertEquals(4F, HydroelectricGeneratorTileEntity.ENERGY_PER_TICK, 0F); + } + @Test public void preservesPendingGeneratorAcrossRepeatedReadSaveWithoutTick() throws Exception { CompoundNBT source = new CompoundNBT(); source.putIntArray("parentPos", new int[] {164, 81, 8}); @@ -56,8 +67,10 @@ public class HydroturbinePersistenceTest { // Only exercise the custom NBT methods; no world, registry or entity tick is needed. private static HydroturbineEntity withoutWorld() throws Exception { - Field field = Unsafe.class.getDeclaredField("theUnsafe"); + Class allocator = Class.forName("sun.misc.Unsafe"); + Field field = allocator.getDeclaredField("theUnsafe"); field.setAccessible(true); - return (HydroturbineEntity) ((Unsafe) field.get(null)).allocateInstance(HydroturbineEntity.class); + return (HydroturbineEntity) allocator.getMethod("allocateInstance", Class.class) + .invoke(field.get(null), HydroturbineEntity.class); } } diff --git a/src/test/java/zone/moddev/mc/electricadvantage/graphics/RendererBufferContractTest.java b/src/test/java/zone/moddev/mc/electricadvantage/graphics/RendererBufferContractTest.java index 97fa9c3..aacd515 100644 --- a/src/test/java/zone/moddev/mc/electricadvantage/graphics/RendererBufferContractTest.java +++ b/src/test/java/zone/moddev/mc/electricadvantage/graphics/RendererBufferContractTest.java @@ -13,7 +13,6 @@ import net.minecraft.util.registry.Bootstrap; import org.junit.BeforeClass; import org.junit.Test; -import sun.misc.Unsafe; import zone.moddev.mc.electricadvantage.init.Power; import zone.moddev.mc.electricadvantage.machines.ElectricDrillTileEntity; import zone.moddev.mc.electricadvantage.machines.LaserTurretTileEntity; @@ -153,10 +152,11 @@ private static void assertNormals(RecordingBuffer buffer) { // Keep the real turret controls; only omit the world-dependent constructor. private static LaserTurretTileEntity turret() throws Exception { - Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + Class allocator = Class.forName("sun.misc.Unsafe"); + Field unsafeField = allocator.getDeclaredField("theUnsafe"); unsafeField.setAccessible(true); LaserTurretTileEntity turret = (LaserTurretTileEntity) - ((Unsafe) unsafeField.get(null)).allocateInstance(LaserTurretTileEntity.class); + allocator.getMethod("allocateInstance", Class.class).invoke(unsafeField.get(null), LaserTurretTileEntity.class); set(TileEntitySimplePowerMachine.class, turret, "types", new ConduitType[] {Power.ELECTRIC_POWER}); set(TileEntitySimplePowerMachine.class, turret, "energyBuffers", new float[] {0}); set(TileEntitySimplePowerMachine.class, turret, "energyBufferSizes", new float[] {2000}); diff --git a/src/test/java/zone/moddev/mc/electricadvantage/gui/GUIHelperTest.java b/src/test/java/zone/moddev/mc/electricadvantage/gui/GUIHelperTest.java new file mode 100644 index 0000000..d575f97 --- /dev/null +++ b/src/test/java/zone/moddev/mc/electricadvantage/gui/GUIHelperTest.java @@ -0,0 +1,29 @@ +package zone.moddev.mc.electricadvantage.gui; + +import org.junit.Test; +import static org.junit.Assert.*; + +public class GUIHelperTest { + @Test public void barRetainsItsEightSegmentScale() { + assertEquals(0, GUIHelper.progressBarWidth(0F)); + assertEquals(17, GUIHelper.progressBarWidth(0.5F)); + assertEquals(33, GUIHelper.progressBarWidth(1F)); + } + + @Test public void invalidAndOversizedValuesCannotEscapeTheTexture() { + for (float value : new float[]{-1F, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Float.NaN}) { + assertEquals(0, GUIHelper.progressBarWidth(value)); + } + assertEquals(33, GUIHelper.progressBarWidth(15F)); + assertEquals(33, GUIHelper.progressBarWidth(Float.MAX_VALUE)); + } + + @Test public void finiteReadingsAreMonotonicAndBounded() { + int previous = 0; + for (int i = -100; i <= 200; i++) { + int width = GUIHelper.progressBarWidth(i / 100F); + assertTrue(width >= previous && width >= 0 && width <= 33); + previous = width; + } + } +} diff --git a/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalNativeDefectsTest.java b/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalNativeDefectsTest.java new file mode 100644 index 0000000..d3f3f9a --- /dev/null +++ b/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalNativeDefectsTest.java @@ -0,0 +1,147 @@ +package zone.moddev.mc.electricadvantage.machines; + +import cyano.poweradvantage.api.fluid.FluidStack; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Collections; +import net.minecraft.block.Blocks; +import net.minecraft.fluid.Fluids; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.RayTraceContext; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.registry.Bootstrap; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import org.junit.BeforeClass; +import org.junit.Test; +import zone.moddev.mc.electricadvantage.init.Power; + +import static org.junit.Assert.*; + +/** Focused regressions for retained independent native operating failures. */ +public class ElectricOperationalNativeDefectsTest { + @BeforeClass public static void bootstrap() { Bootstrap.bootStrap(); } + + @Test public void controllerCannotRequestMoreThanItsHundredUnitElectricalBuffer() throws Exception { + GrowthChamberControllerTileEntity controller = controller(); + assertEquals(100, controller.getPowerRequest(Power.ELECTRIC_POWER).amount, 0); + assertEquals(0, controller.getEnergy(Power.ELECTRIC_POWER), 0); + assertEquals(1000, controller.getSoil(), 0); + assertEquals(1800, controller.getTank().getFluidAmount()); + } + + @Test public void controllerSubtractsElectricityAlreadyStoredFromInputCapacity() throws Exception { + GrowthChamberControllerTileEntity controller = controller(); + controller.setEnergy(40, Power.ELECTRIC_POWER); + assertEquals(60, controller.getPowerRequest(Power.ELECTRIC_POWER).amount, 0); + controller.setEnergy(100, Power.ELECTRIC_POWER); + assertEquals(0, controller.getPowerRequest(Power.ELECTRIC_POWER).amount, 0); + } + + @Test public void scarceResourcesAndExistingElectricityBoundTheRemainingDemand() throws Exception { + GrowthChamberControllerTileEntity controller = controller(); + controller.setSoil(1); + controller.getTank().setFluid(new FluidStack(Fluids.WATER, 2)); + controller.setEnergy(4, Power.ELECTRIC_POWER); + assertEquals(4, controller.getPowerRequest(Power.ELECTRIC_POWER).amount, 0); + controller.setEnergy(999.75f, Power.GROWTHCHAMBER_POWER); + assertEquals(0, controller.getPowerRequest(Power.ELECTRIC_POWER).amount, 0); + } + + @Test public void fullGreenhouseBufferCannotRequestMoreElectricity() throws Exception { + GrowthChamberControllerTileEntity controller = controller(); + controller.setEnergy(1000, Power.GROWTHCHAMBER_POWER); + assertEquals(0, controller.getPowerRequest(Power.ELECTRIC_POWER).amount, 0); + } + + @Test public void panelSamplesIncidentLightAboveItsSolidBody() throws Exception { + LightWorld world = withoutConstructor(LightWorld.class); + BlockPos panel = new BlockPos(101, 82, -27); + world.surface = panel.above(); + world.brightness = 14; + assertEquals(0.1f * 14 * 0.0666666f, + PhotovoltaicGeneratorTileEntity.getLightIntensityAt(panel, world), 0.000001f); + assertEquals(1, world.skyReads); + assertEquals(1, world.lightReads); + } + + @Test public void darkPanelSurfaceProducesNoBlocklightPower() throws Exception { + LightWorld world = withoutConstructor(LightWorld.class); + BlockPos panel = new BlockPos(101, 82, -27); + world.surface = panel.above(); + assertEquals(0, PhotovoltaicGeneratorTileEntity.getLightIntensityAt(panel, world), 0); + } + + @Test public void beamIgnoresOnlyItsOwnCollisionPostAndStopsAtTheDeclaredRange() throws Exception { + BeamWorld world = withoutConstructor(BeamWorld.class); + world.turret = new BlockPos(101, 82, -27); + StubTurret turret = withoutConstructor(StubTurret.class); + turret.testWorld = world; + turret.setPosition(world.turret); + Vector3d origin = new Vector3d(101.5, 82.75, -26.5); + Method trace = LaserTurretTileEntity.class.getDeclaredMethod("followRayToSolidBlock", + Vector3d.class, Vector3d.class, double.class); + trace.setAccessible(true); + Vector3d end = (Vector3d)trace.invoke(turret, origin, new Vector3d(1, 0, 0), 32.0); + assertEquals(1, world.traces); + assertEquals(32, origin.distanceTo(end), 0.000001); + } + + private static GrowthChamberControllerTileEntity controller() throws Exception { + GrowthChamberControllerTileEntity controller = new GrowthChamberControllerTileEntity(); + controller.setSoil(1000); + controller.getTank().setFluid(new FluidStack(Fluids.WATER, 1800)); + Field redstone = GrowthChamberControllerTileEntity.class.getDeclaredField("redstone"); + redstone.setAccessible(true); + redstone.setBoolean(controller, false); + return controller; + } + + private static T withoutConstructor(Class type) throws Exception { + Class allocator = Class.forName("sun.misc.Unsafe"); + Field field = allocator.getDeclaredField("theUnsafe"); + field.setAccessible(true); + return type.cast(allocator.getMethod("allocateInstance", Class.class).invoke(field.get(null), type)); + } + + private static final class LightWorld extends ServerWorld { + BlockPos surface; + int brightness, skyReads, lightReads; + private LightWorld() { + super(null, null, null, null, null, null, null, null, false, 0L, Collections.emptyList(), false); + } + @Override public boolean canSeeSky(BlockPos pos) { + assertEquals("Sky access must be sampled above the solid panel", surface, pos); + skyReads++; + return false; + } + @Override public int getMaxLocalRawBrightness(BlockPos pos) { + assertEquals("Incident block light must be sampled above the solid panel", surface, pos); + lightReads++; + return brightness; + } + } + + private static final class BeamWorld extends ServerWorld { + BlockPos turret; + int traces; + private BeamWorld() { + super(null, null, null, null, null, null, null, null, false, 0L, Collections.emptyList(), false); + } + @Override public BlockRayTraceResult clip(RayTraceContext context) { + traces++; + assertTrue("Owning turret post must not stop its own beam", + context.getBlockShape(new LaserTurretBlock(false).defaultBlockState(), this, turret).isEmpty()); + assertFalse("An immediately adjacent solid block must still stop the beam", + context.getBlockShape(Blocks.STONE.defaultBlockState(), this, turret.east()).isEmpty()); + return BlockRayTraceResult.miss(context.getTo(), Direction.EAST, new BlockPos(context.getTo())); + } + } + + private static final class StubTurret extends LaserTurretTileEntity { + World testWorld; + @Override public World getLevel() { return testWorld; } + } +} diff --git a/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalPumpPickupTest.java b/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalPumpPickupTest.java new file mode 100644 index 0000000..4a6fee0 --- /dev/null +++ b/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalPumpPickupTest.java @@ -0,0 +1,205 @@ +package zone.moddev.mc.electricadvantage.machines; + +import cyano.poweradvantage.api.fluid.FluidStack; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.FlowingFluidBlock; +import net.minecraft.block.IBucketPickupHandler; +import net.minecraft.block.SlabBlock; +import net.minecraft.block.StairsBlock; +import net.minecraft.block.material.Material; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.FluidState; +import net.minecraft.fluid.Fluids; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.state.properties.Half; +import net.minecraft.state.properties.SlabType; +import net.minecraft.state.properties.StairsShape; +import net.minecraft.util.Direction; +import net.minecraft.util.SoundEvent; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Bootstrap; +import net.minecraft.world.IWorld; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import org.junit.BeforeClass; +import org.junit.Test; +import zone.moddev.mc.electricadvantage.init.Power; + +import static org.junit.Assert.*; + +/** Focused pickup transitions; the independent rig covers natural server ticks. */ +public class ElectricOperationalPumpPickupTest { + private static final BlockPos PUMP = new BlockPos(8, 84, 8); + private static final BlockPos SOURCE = PUMP.below().north(); + private static final float RESERVE = 8000; + private static final float PICKUP_COST = 1000 + 32; + + @BeforeClass public static void bootstrap() { Bootstrap.bootStrap(); } + + @Test public void waterloggedSlabKeepsItsBlockAndSlabType() throws Exception { + BlockState wet = Blocks.OAK_SLAB.defaultBlockState() + .setValue(SlabBlock.TYPE, SlabType.TOP) + .setValue(BlockStateProperties.WATERLOGGED, true); + StubPump pump = fixture(wet); + pump.tickUpdate(true); + assertSuccessfulPickup(pump, Fluids.WATER); + assertEquals(wet.setValue(BlockStateProperties.WATERLOGGED, false), pump.testWorld.getBlockState(SOURCE)); + assertEquals(1, pump.testWorld.writes); + } + + @Test public void waterloggedStairsKeepFacingHalfAndShape() throws Exception { + BlockState wet = Blocks.OAK_STAIRS.defaultBlockState() + .setValue(StairsBlock.FACING, Direction.SOUTH) + .setValue(StairsBlock.HALF, Half.TOP) + .setValue(StairsBlock.SHAPE, StairsShape.OUTER_LEFT) + .setValue(BlockStateProperties.WATERLOGGED, true); + StubPump pump = fixture(wet); + pump.tickUpdate(true); + assertSuccessfulPickup(pump, Fluids.WATER); + assertEquals(wet.setValue(BlockStateProperties.WATERLOGGED, false), pump.testWorld.getBlockState(SOURCE)); + assertEquals(1, pump.testWorld.writes); + } + + @Test public void ordinaryWaterAndLavaSourcesStillYieldOneBucket() throws Exception { + for (Block block : new Block[]{Blocks.WATER, Blocks.LAVA}) { + StubPump pump = fixture(block.defaultBlockState()); + pump.tickUpdate(true); + assertSuccessfulPickup(pump, block == Blocks.WATER ? Fluids.WATER : Fluids.LAVA); + assertEquals(Blocks.AIR.defaultBlockState(), pump.testWorld.getBlockState(SOURCE)); + assertEquals(1, pump.testWorld.writes); + } + } + + @Test public void sourceWaterInsideNonPickupSeagrassIsNotDestroyed() throws Exception { + StubPump pump = fixture(Blocks.SEAGRASS.defaultBlockState()); + assertTrue(pump.testWorld.getFluidState(SOURCE).isSource()); + assertFalse(pump.testWorld.getBlockState(SOURCE).getBlock() instanceof IBucketPickupHandler); + pump.tickUpdate(true); + assertUntouched(pump, Blocks.SEAGRASS.defaultBlockState(), RESERVE, 0); + } + + @Test public void refusedOrNullPickupDoesNotInventFluidOrDebitElectricity() throws Exception { + for (boolean returnNull : new boolean[]{false, true}) { + RefusingSource block = new RefusingSource(returnNull); + StubPump pump = fixture(block.defaultBlockState()); + pump.tickUpdate(true); + assertEquals(1, block.calls); + assertUntouched(pump, block.defaultBlockState(), RESERVE, 0); + } + } + + @Test public void insufficientElectricityDoesNotCallPickup() throws Exception { + RefusingSource block = new RefusingSource(false); + StubPump pump = fixture(block.defaultBlockState()); + pump.setEnergy(PICKUP_COST - 1, Power.ELECTRIC_POWER); + pump.tickUpdate(true); + assertEquals(0, block.calls); + assertUntouched(pump, block.defaultBlockState(), PICKUP_COST - 1, 0); + } + + @Test public void occupiedTankDoesNotCallPickupOrOverwriteItsFluid() throws Exception { + RefusingSource block = new RefusingSource(false); + StubPump pump = fixture(block.defaultBlockState()); + pump.getTank().setFluid(new FluidStack(Fluids.LAVA, 1)); + pump.tickUpdate(true); + assertEquals(0, block.calls); + assertUntouched(pump, block.defaultBlockState(), RESERVE, 1); + assertSame(Fluids.LAVA, pump.getTank().getFluid().getFluid()); + } + + @Test public void flowingWaterAndDrySlabsCannotBePickedUpAsSources() throws Exception { + for (BlockState state : new BlockState[]{ + Blocks.WATER.defaultBlockState().setValue(FlowingFluidBlock.LEVEL, 1), + Blocks.OAK_SLAB.defaultBlockState()}) { + StubPump pump = fixture(state); + pump.tickUpdate(true); + assertUntouched(pump, state, RESERVE, 0); + } + } + + private static StubPump fixture(BlockState source) throws Exception { + PumpWorld world = withoutConstructor(PumpWorld.class); + world.blocks = new HashMap<>(); + world.blocks.put(SOURCE, source); + StubPump pump = new StubPump(); + pump.testWorld = world; + pump.setPosition(PUMP); + pump.setEnergy(RESERVE, Power.ELECTRIC_POWER); + CompoundNBT patch = new CompoundNBT(); + patch.putByte("NextPump", (byte)0); + pump.loadFrom(patch); + return pump; + } + + private static void assertSuccessfulPickup(StubPump pump, Fluid expected) { + assertEquals(1000, pump.getTank().getFluidAmount()); + assertSame(expected, pump.getTank().getFluid().getFluid()); + assertEquals(RESERVE - PICKUP_COST, pump.getEnergy(Power.ELECTRIC_POWER), 0); + assertEquals(2, pump.sounds); + } + + private static void assertUntouched(StubPump pump, BlockState expected, float energy, int fluid) { + assertEquals(expected, pump.testWorld.getBlockState(SOURCE)); + assertEquals(0, pump.testWorld.writes); + assertEquals(energy, pump.getEnergy(Power.ELECTRIC_POWER), 0); + assertEquals(fluid, pump.getTank().getFluidAmount()); + assertEquals(0, pump.sounds); + } + + private static T withoutConstructor(Class type) throws Exception { + Class allocator = Class.forName("sun.misc.Unsafe"); + Field field = allocator.getDeclaredField("theUnsafe"); + field.setAccessible(true); + return type.cast(allocator.getMethod("allocateInstance", Class.class).invoke(field.get(null), type)); + } + + private static final class StubPump extends ElectricPumpTileEntity { + PumpWorld testWorld; + int sounds; + @Override public World getLevel() { return testWorld; } + @Override protected boolean hasRedstoneSignal() { return false; } + @Override protected void playSoundEffect(double x, double y, double z, SoundEvent sound, float volume, float pitch) { + sounds++; + } + } + + private static final class PumpWorld extends ServerWorld { + Map blocks; + int writes; + private PumpWorld() { + super(null, null, null, null, null, null, null, null, false, 0L, Collections.emptyList(), false); + } + @Override public boolean hasChunkAt(BlockPos pos) { return true; } + @Override public BlockState getBlockState(BlockPos pos) { + return blocks.getOrDefault(pos, Blocks.STONE.defaultBlockState()); + } + @Override public FluidState getFluidState(BlockPos pos) { return getBlockState(pos).getFluidState(); } + @Override public boolean isEmptyBlock(BlockPos pos) { return getBlockState(pos).isAir(); } + @Override public boolean setBlock(BlockPos pos, BlockState state, int flags) { + writes++; + blocks.put(pos.immutable(), state); + return true; + } + } + + private static final class RefusingSource extends Block implements IBucketPickupHandler { + final boolean returnNull; + int calls; + RefusingSource(boolean returnNull) { + super(Block.Properties.of(Material.STONE)); + this.returnNull = returnNull; + } + @Override public FluidState getFluidState(BlockState state) { return Fluids.WATER.getSource(false); } + @Override public Fluid takeLiquid(IWorld world, BlockPos pos, BlockState state) { + calls++; + return returnNull ? null : Fluids.EMPTY; + } + } +} diff --git a/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalRedstoneCacheTest.java b/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalRedstoneCacheTest.java new file mode 100644 index 0000000..1257255 --- /dev/null +++ b/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalRedstoneCacheTest.java @@ -0,0 +1,218 @@ +package zone.moddev.mc.electricadvantage.machines; + +import cyano.poweradvantage.api.PoweredEntity; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Bootstrap; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** Initial interlock sampling must not turn the ordinary cache into per-tick polling. */ +public class ElectricOperationalRedstoneCacheTest { + private static final BlockPos EVEN = new BlockPos(8, 80, 8); + private static final BlockPos ODD = new BlockPos(9, 81, 9); + + @BeforeClass public static void bootstrap() { Bootstrap.bootStrap(); } + + @Test public void signalledFirstUseDoesNotWaitForPowerUpdate() throws Exception { + ProbeMachine machine = fixture(EVEN, true); + assertTrue(machine.signal()); + assertEquals(1, machine.testWorld.queryTimes.size()); + machine.testWorld.signalled = false; + assertTrue("Repeated reads must retain the sampled interlock", machine.signal()); + assertEquals(1, machine.testWorld.queryTimes.size()); + } + + @Test public void unsignalledFirstUseIsSampledAndCachedToo() throws Exception { + ProbeMachine machine = fixture(EVEN, false); + assertFalse(machine.signal()); + assertEquals(1, machine.testWorld.queryTimes.size()); + machine.testWorld.signalled = true; + assertFalse("A cached false must not be mistaken for uninitialized", machine.signal()); + assertEquals(1, machine.testWorld.queryTimes.size()); + } + + @Test public void unattachedReadDoesNotInitializeTheWorldCache() throws Exception { + ProbeMachine machine = new ProbeMachine(); + machine.setPosition(EVEN); + assertFalse(machine.signal()); + machine.testWorld = world(EVEN, true); + assertTrue(machine.signal()); + assertEquals(1, machine.testWorld.queryTimes.size()); + } + + @Test public void clientReadsNeitherQueryRedstoneNorInitializeTheCache() throws Exception { + ProbeMachine machine = fixture(EVEN, true); + SignalWorld client = machine.testWorld; + Field clientSide = World.class.getDeclaredField("isClientSide"); + clientSide.setAccessible(true); + clientSide.setBoolean(client, true); + assertTrue(client.isClientSide); + assertFalse(machine.signal()); + client.signalled = false; + assertFalse(machine.signal()); + assertTrue("Client reads must not query local redstone", client.queryTimes.isEmpty()); + machine.testWorld = world(EVEN, true); + assertTrue("Client reads must not initialize the server cache", machine.signal()); + assertEquals(1, machine.testWorld.queryTimes.size()); + } + + @Test public void powerUpdateBeforeFirstUseAlreadyInitializesTheCache() throws Exception { + ProbeMachine machine = fixture(EVEN, true); + machine.powerUpdate(); + assertEquals(1, machine.testWorld.queryTimes.size()); + machine.testWorld.signalled = false; + assertTrue(machine.signal()); + assertEquals("First use after powerUpdate must not resample", 1, machine.testWorld.queryTimes.size()); + } + + @Test public void realPoweredTickKeepsBothEdgesCachedUntilTheEightTickRefresh() throws Exception { + for (BlockPos position : new BlockPos[]{EVEN, ODD}) { + for (boolean initial : new boolean[]{false, true}) { + ProbeMachine machine = fixture(position, initial); + SignalWorld world = machine.testWorld; + long refresh = position.equals(EVEN) ? 8 : 9; + long first = refresh - 7; + world.time = first; + machine.tick(); + assertEquals(initial, machine.observed); + assertEquals(1, world.queryTimes.size()); + world.signalled = !initial; + for (long tick = first + 1; tick <= refresh + 8; tick++) { + world.time = tick; + machine.tick(); + assertEquals("tickUpdate must precede the scheduled refresh at " + tick, + tick <= refresh ? initial : !initial, machine.observed); + assertEquals(tick < refresh ? 1 : tick < refresh + 8 ? 2 : 3, world.queryTimes.size()); + } + assertEquals(Arrays.asList(first, refresh, refresh + 8), world.queryTimes); + assertEquals(2, machine.powerUpdates); + } + } + } + + private static ProbeMachine fixture(BlockPos position, boolean signalled) throws Exception { + ProbeMachine machine = new ProbeMachine(); + machine.setPosition(position); + machine.testWorld = world(position, signalled); + // Isolate conduit discovery, not PoweredEntity's real power-update cadence. + Field delay = PoweredEntity.class.getDeclaredField("conduitRefreshDelay"); + delay.setAccessible(true); + delay.setInt(machine, -1); + return machine; + } + + private static SignalWorld world(BlockPos position, boolean signalled) throws Exception { + Class allocator = Class.forName("sun.misc.Unsafe"); + Field field = allocator.getDeclaredField("theUnsafe"); + field.setAccessible(true); + SignalWorld world = (SignalWorld)allocator.getMethod("allocateInstance", Class.class) + .invoke(field.get(null), SignalWorld.class); + world.position = position; + world.signalled = signalled; + world.queryTimes = new ArrayList<>(); + return world; + } + + private static final class ProbeMachine extends ElectricOvenTileEntity { + SignalWorld testWorld; + boolean observed; + int powerUpdates; + boolean signal() { return hasRedstoneSignal(); } + @Override public World getLevel() { return testWorld; } + @Override public void tickUpdate(boolean server) { observed = hasRedstoneSignal(); } + @Override public void powerUpdate() { + powerUpdates++; + super.powerUpdate(); + } + @Override protected void setPowerState(boolean powered) { } + } + + @Test public void generatorSamplesSignalledFirstUseBeforeItsFirstPulse() throws Exception { + ProbeGenerator generator = generatorFixture(true); + assertTrue("A newly loaded generator must observe redstone before generating", generator.signal()); + assertEquals(1, generator.testWorld.queryTimes.size()); + generator.testWorld.signalled = false; + assertTrue("First-use sampling must retain the normal cached value", generator.signal()); + assertEquals(1, generator.testWorld.queryTimes.size()); + } + + @Test public void generatorCachesAnUnsignalledFirstReadToo() throws Exception { + ProbeGenerator generator = generatorFixture(false); + assertFalse(generator.signal()); + assertEquals(1, generator.testWorld.queryTimes.size()); + generator.testWorld.signalled = true; + assertFalse("A false interlock sample is initialized, not missing", generator.signal()); + assertEquals(1, generator.testWorld.queryTimes.size()); + } + + @Test public void unattachedGeneratorReadDoesNotInitializeItsCache() throws Exception { + ProbeGenerator generator = new ProbeGenerator(); + generator.setPosition(EVEN); + assertFalse(generator.signal()); + generator.testWorld = world(EVEN, true); + assertTrue(generator.signal()); + assertEquals(1, generator.testWorld.queryTimes.size()); + } + + @Test public void clientGeneratorReadCannotInitializeTheServerCache() throws Exception { + ProbeGenerator generator = generatorFixture(true); + Field clientSide = World.class.getDeclaredField("isClientSide"); + clientSide.setAccessible(true); + clientSide.setBoolean(generator.testWorld, true); + assertFalse(generator.signal()); + assertTrue(generator.testWorld.queryTimes.isEmpty()); + generator.testWorld = world(EVEN, true); + assertTrue("A client-only read must leave the server interlock unsampled", generator.signal()); + assertEquals(1, generator.testWorld.queryTimes.size()); + } + + @Test public void inhibitedSolarGeneratorCannotGenerateItsFirstPulse() throws Exception { + ProbeGenerator generator = generatorFixture(true); + generator.powerUpdate(); + assertEquals("Redstone is sampled before generation, then on the ordinary refresh", 2, + generator.testWorld.queryTimes.size()); + assertEquals(0, generator.getEnergy(), 0); + assertEquals(0, generator.getPowerOutput(), 0); + } + + private static ProbeGenerator generatorFixture(boolean signalled) throws Exception { + ProbeGenerator generator = new ProbeGenerator(); + generator.setPosition(EVEN); + generator.testWorld = world(EVEN, signalled); + return generator; + } + + private static final class ProbeGenerator extends PhotovoltaicGeneratorTileEntity { + SignalWorld testWorld; + boolean signal() { return hasRedstoneSignal(); } + @Override public World getLevel() { return testWorld; } + } + + private static final class SignalWorld extends ServerWorld { + @Override public boolean canSeeSky(BlockPos position) { + throw new AssertionError("An inhibited panel must not enter light sampling"); + } + BlockPos position; + boolean signalled; + long time; + List queryTimes; + private SignalWorld() { + super(null, null, null, null, null, null, null, null, false, 0L, Collections.emptyList(), false); + } + @Override public boolean hasNeighborSignal(BlockPos position) { + assertEquals(this.position, position); + queryTimes.add(time); + return signalled; + } + @Override public long getGameTime() { return time; } + } +} diff --git a/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalSoundBroadcastTest.java b/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalSoundBroadcastTest.java new file mode 100644 index 0000000..1c0ae73 --- /dev/null +++ b/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalSoundBroadcastTest.java @@ -0,0 +1,128 @@ +package zone.moddev.mc.electricadvantage.machines; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Predicate; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.IPacket; +import net.minecraft.network.play.ServerPlayNetHandler; +import net.minecraft.network.play.server.SPlaySoundPacket; +import net.minecraft.util.SoundEvents; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.registry.Bootstrap; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** Real broadcast methods with an explicit player list and forbidden chunk-backed entity queries. */ +public class ElectricOperationalSoundBroadcastTest { + @BeforeClass public static void bootstrap() { Bootstrap.bootStrap(); } + + @Test public void machineBroadcastUsesOnlyExistingIntersectingConnectedPlayers() throws Exception { + QueryRejectingWorld world = fixture(); + ElectricOvenTileEntity machine = new ElectricOvenTileEntity() { + @Override public World getLevel() { return world; } + }; + machine.playSoundEffect(100, 80, -20, SoundEvents.ANVIL_LAND, 0.25f, 0.75f); + assertRecipients(world); + } + + @Test public void generatorBroadcastUsesOnlyExistingIntersectingConnectedPlayers() throws Exception { + QueryRejectingWorld world = fixture(); + PhotovoltaicGeneratorTileEntity generator = new PhotovoltaicGeneratorTileEntity() { + @Override public World getLevel() { return world; } + }; + generator.playSoundEffect(100, 80, -20, SoundEvents.ANVIL_LAND, 0.25f, 0.75f); + assertRecipients(world); + } + + @Test public void emptyPlayerListNeverQueriesChunks() throws Exception { + QueryRejectingWorld world = withoutConstructor(QueryRejectingWorld.class); + world.existingPlayers = Collections.emptyList(); + ElectricOvenTileEntity machine = new ElectricOvenTileEntity() { + @Override public World getLevel() { return world; } + }; + machine.playSoundEffect(50000, 82, 50000, SoundEvents.ANVIL_LAND, 1, 1); + assertEquals(1, world.playerListReads); + } + + private static QueryRejectingWorld fixture() throws Exception { + QueryRejectingWorld world = withoutConstructor(QueryRejectingWorld.class); + world.existingPlayers = new ArrayList<>(); + world.existingPlayers.add(player(new AxisAlignedBB(99.7, 80, -20.3, 100.3, 81.8, -19.7), false, true)); + // Player center can be outside 16 blocks while its box still intersects the original cube. + world.existingPlayers.add(player(new AxisAlignedBB(115.9, 80, -20.3, 116.5, 81.8, -19.7), false, true)); + // Cube corner is outside a spherical range but was included by the original AABB query. + world.existingPlayers.add(player(new AxisAlignedBB(115, 80, -5, 115.6, 81.8, -4.4), false, true)); + world.existingPlayers.add(player(new AxisAlignedBB(116, 80, -20.3, 116.6, 81.8, -19.7), false, true)); + world.existingPlayers.add(player(new AxisAlignedBB(99.7, 96, -20.3, 100.3, 97.8, -19.7), false, true)); + world.existingPlayers.add(player(new AxisAlignedBB(99.7, 62.2, -20.3, 100.3, 64, -19.7), false, true)); + world.existingPlayers.add(player(new AxisAlignedBB(99.7, 80, -20.3, 100.3, 81.8, -19.7), true, true)); + world.existingPlayers.add(player(new AxisAlignedBB(99.7, 80, -20.3, 100.3, 81.8, -19.7), false, false)); + return world; + } + + private static StubPlayer player(AxisAlignedBB bounds, boolean spectator, boolean connected) throws Exception { + StubPlayer player = withoutConstructor(StubPlayer.class); + player.setBoundingBox(bounds); + player.spectator = spectator; + if (connected) player.connection = withoutConstructor(RecordingConnection.class); + return player; + } + + private static void assertRecipients(QueryRejectingWorld world) { + assertEquals("Broadcast reads the existing player list once", 1, world.playerListReads); + for (int i = 0; i < world.existingPlayers.size(); i++) { + ServerPlayerEntity player = world.existingPlayers.get(i); + if (player.connection == null) continue; + RecordingConnection connection = (RecordingConnection)player.connection; + assertEquals("Player " + i, i < 3 ? 1 : 0, connection.sent); + if (i < 3) assertTrue(connection.last instanceof SPlaySoundPacket); + } + } + + private static T withoutConstructor(Class type) throws Exception { + Class allocator = Class.forName("sun.misc.Unsafe"); + Field field = allocator.getDeclaredField("theUnsafe"); + field.setAccessible(true); + return type.cast(allocator.getMethod("allocateInstance", Class.class).invoke(field.get(null), type)); + } + + private static final class QueryRejectingWorld extends ServerWorld { + List existingPlayers; + int playerListReads; + + private QueryRejectingWorld() { + super(null, null, null, null, null, null, null, null, false, 0L, Collections.emptyList(), false); + } + + @Override public List players() { + playerListReads++; + return existingPlayers; + } + + @Override public List getEntitiesOfClass(Class type, + AxisAlignedBB bounds, Predicate predicate) { + throw new AssertionError("Sound broadcast must not use chunk-backed entity queries"); + } + } + + private static final class StubPlayer extends ServerPlayerEntity { + boolean spectator; + private StubPlayer() { super(null, null, null, null); } + @Override public boolean isSpectator() { return spectator; } + } + + private static final class RecordingConnection extends ServerPlayNetHandler { + int sent; + IPacket last; + private RecordingConnection() { super(null, null, null); } + @Override public void send(IPacket packet) { sent++; last = packet; } + } +} diff --git a/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalStillCapacityTest.java b/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalStillCapacityTest.java new file mode 100644 index 0000000..cc09173 --- /dev/null +++ b/src/test/java/zone/moddev/mc/electricadvantage/machines/ElectricOperationalStillCapacityTest.java @@ -0,0 +1,68 @@ +package zone.moddev.mc.electricadvantage.machines; + +import cyano.poweradvantage.api.fluid.FluidStack; +import java.lang.reflect.Method; +import net.minecraft.fluid.Fluids; +import net.minecraft.util.registry.Bootstrap; +import org.junit.BeforeClass; +import org.junit.Test; +import zone.moddev.mc.poweradvantage.registry.still.recipe.DistillationRecipe; +import zone.moddev.mc.poweradvantage.registry.still.recipe.ExplicitFluidReference; + +import static org.junit.Assert.*; + +/** Capacity preflight tests; the shared rig separately tests natural machine ticks. */ +public class ElectricOperationalStillCapacityTest { + @BeforeClass public static void bootstrap() { Bootstrap.bootStrap(); } + + @Test public void aFullTankCannotConsumeInput() throws Exception { + ElectricStillTileEntity still = fixture(1000); + assertFalse(preview(still)); + assertEquals(4, still.getInputTank().getFluidAmount()); + assertEquals(1000, still.getOutputTank().getFluidAmount()); + } + + @Test public void aPartialOutputMustFitTheWholeRecipe() throws Exception { + ElectricStillTileEntity still = fixture(998); + assertFalse(preview(still)); + assertEquals(4, still.getInputTank().getFluidAmount()); + assertEquals(998, still.getOutputTank().getFluidAmount()); + } + + @Test public void exactSpaceIsAcceptedWithoutMutatingEitherTank() throws Exception { + ElectricStillTileEntity still = fixture(997); + assertTrue(preview(still)); + assertEquals(4, still.getInputTank().getFluidAmount()); + assertEquals(997, still.getOutputTank().getFluidAmount()); + } + + @Test public void incompatibleOutputCannotBeOverwritten() throws Exception { + ElectricStillTileEntity still = fixture(0); + still.getOutputTank().setFluid(new FluidStack(Fluids.WATER, 1)); + assertFalse(preview(still)); + assertEquals(Fluids.WATER, still.getOutputTank().getFluid().getFluid()); + assertEquals(4, still.getInputTank().getFluidAmount()); + } + + @Test public void anIncompleteInputDoesNotInventAnOutput() throws Exception { + ElectricStillTileEntity still = fixture(0); + still.getInputTank().setFluid(new FluidStack(Fluids.WATER, 1)); + assertFalse(preview(still)); + assertEquals(1, still.getInputTank().getFluidAmount()); + } + + private static ElectricStillTileEntity fixture(int output) { + ElectricStillTileEntity still = new ElectricStillTileEntity(); + still.getInputTank().setFluid(new FluidStack(Fluids.WATER, 4)); + if (output > 0) still.getOutputTank().setFluid(new FluidStack(Fluids.LAVA, output)); + return still; + } + + private static boolean preview(ElectricStillTileEntity still) throws Exception { + DistillationRecipe recipe = new DistillationRecipe(new ExplicitFluidReference(Fluids.WATER), 2, + new ExplicitFluidReference(Fluids.LAVA), 3); + Method method = ElectricStillTileEntity.class.getDeclaredMethod("hasSpaceForDistillation", DistillationRecipe.class); + method.setAccessible(true); + return (Boolean)method.invoke(still, recipe); + } +} diff --git a/tools/verification/Verify-ElectricEcj.ps1 b/tools/verification/Verify-ElectricEcj.ps1 index 86c7e05..f941090 100644 --- a/tools/verification/Verify-ElectricEcj.ps1 +++ b/tools/verification/Verify-ElectricEcj.ps1 @@ -39,8 +39,12 @@ function Invoke-Ecj([string]$Name, [string[]]$Sources, [string[]]$Libraries) { $output = Join-Path $Evidence $Name $null = New-Item -ItemType Directory -Path $output $xmlLog = Join-Path $Evidence "$Name.xml" - $arguments = @('-1.8', '-proc:none', '-encoding', 'UTF-8', '-bootclasspath', - ('"' + (($bootLibraries.path -replace '\\', '/') -join ';') + '"'), '-classpath', + # Match Eclipse's Java 8 JRE access restrictions, not just its compiler version. + $restrictedBoot = @($bootLibraries.path | ForEach-Object { + $_.Replace('\', '/') + '[-sun/**;-com/sun/**;-jdk/internal/**]' + }) + $arguments = @('-1.8', '-proc:none', '-encoding', 'UTF-8', '-err:+forbidden,discouraged', '-bootclasspath', + ('"' + ($restrictedBoot -join ';') + '"'), '-classpath', ('"' + (($Libraries -replace '\\', '/') -join ';') + '"'), '-d', ('"' + $output.Replace('\', '/') + '"'), '-log', ('"' + $xmlLog.Replace('\', '/') + '"')) $arguments += @($Sources | ForEach-Object { '"' + $_.Replace('\', '/') + '"' }) @@ -114,7 +118,7 @@ try { $expected += [int]$inventory.testsuite.tests $report.gradleInventory += Get-Pin $xml.FullName } - if ($classes.Count -ne 17 -or $expected -ne 47 -or $sources.test.Count -ne 17 -or $sources.main.Count -ne 85) { throw 'Unexpected Electric 1.16.5 source/test inventory' } + if ($classes.Count -ne 18 -or $expected -ne 51 -or $sources.test.Count -ne 18 -or $sources.main.Count -ne 85) { throw 'Unexpected Electric 1.16.5 source/test inventory' } $main = Invoke-Ecj 'main' $sources.main $mainLibraries $test = Invoke-Ecj 'test' $sources.test (@($main) + $testLibraries) $helperSource = Join-Path $PSScriptRoot 'AuditedJUnit.java' From ef2e22b264a7110c52c072d7f56c2b015ff162d2 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Fri, 30 Oct 2026 20:57:39 +0000 Subject: [PATCH 12/12] Clarify public source status without changing qualification records --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e2a0c24..caf01a4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Electric Advantage -**Minecraft 1.16.5 port candidate, version 2.2.8.116051.** +**Minecraft 1.16.5 source port candidate, version 2.2.8.116051.** The follow-up checks measure finite machine jobs, energy and fluid conservation, blocked routes, real turret hits and full-process restarts. Rendered GUI checks require the correct labels as well as correctly placed controls. The shared @@ -10,8 +10,7 @@ checks retain a separately controlled vanilla wolf-health difference. Manual acceptance is pending. This is not a published release. See [the native port checklist](docs/NATIVE116.md). The [shared test record](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.16.5/docs/1.16/CURRENT-QUALIFICATION.md) -records the exact jars, completed checks and remaining limits. That page will be -available upstream when this local port is merged. +records the exact jars, completed checks and remaining limits. The [accepted 1.15 record](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.15.2/docs/1.15/CURRENT-QUALIFICATION.md) is a behavior reference, not evidence that this target passes. @@ -35,8 +34,8 @@ Build inputs are separate, non-embedded deobfuscated jars: Exact checksums are recorded in `gradle.properties`. Power deobf SHA-256 is `2FB923944A456B4F26AB2F9212C646469CE3F49BFD4DAE894C15559B48908386`. -Its source is local-only; hosted reproducibility is pending upstream source -publication. Do not bypass the release audits or substitute a preliminary jar. +The pinned Power source is available upstream. Do not bypass the release audits +or substitute a preliminary jar. Use immutable copies for verification, not a sibling's output that another build may replace. CI rejects pins that differ from this audited candidate.