From 70920e812c78dcd61fe50627d56853f6cad7f380 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 12:18:11 +0000 Subject: [PATCH 1/9] Bring Steam Advantage to Minecraft 1.16.5 --- .github/workflows/ci.yml | 45 ++-- .github/workflows/codeql-analysis.yml | 31 ++- .github/workflows/validate-gradle-build.yml | 4 +- CHANGELOG.txt | 12 ++ README.md | 125 +++++------ build.gradle | 58 +++--- gradle.properties | 39 ++-- .../mc/steamadvantage/SteamAdvantage.java | 6 +- .../steamadvantage/blocks/DrillBitBlock.java | 28 +-- .../blocks/DrillBitTileEntity.java | 48 ++--- .../steamadvantage/blocks/PlatformBlock.java | 28 +-- .../steamadvantage/blocks/PumpPipeBlock.java | 20 +- .../blocks/SteamTrackBlock.java | 10 +- .../compat/BaseMetalsCompat.java | 4 +- .../HighExplosiveEnchantment.java | 12 +- .../enchantments/PowderlessEnchantment.java | 10 +- .../enchantments/RapidReloadEnchantment.java | 10 +- .../enchantments/RecoilEnchantment.java | 12 +- .../graphics/ClientRegistration.java | 15 +- .../graphics/DrillBitRenderer.java | 22 +- .../steamadvantage/gui/BlastFurnaceGUI.java | 6 +- .../mc/steamadvantage/gui/CoalBoilerGUI.java | 2 +- .../steamadvantage/gui/ElectricBoilerGUI.java | 2 +- .../mc/steamadvantage/gui/GUIHelper.java | 8 +- .../gui/GeothermalBoilerGUI.java | 2 +- .../mc/steamadvantage/gui/OilBoilerGUI.java | 2 +- .../mc/steamadvantage/gui/RockCrusherGUI.java | 2 +- .../mc/steamadvantage/gui/SteamDrillGUI.java | 2 +- .../mc/steamadvantage/gui/SteamPumpGUI.java | 2 +- .../mc/steamadvantage/gui/SteamStillGUI.java | 2 +- .../mc/steamadvantage/gui/SteamTankGUI.java | 2 +- .../moddev/mc/steamadvantage/init/Blocks.java | 4 +- .../mc/steamadvantage/init/Entities.java | 2 +- .../moddev/mc/steamadvantage/init/Items.java | 4 +- .../mc/steamadvantage/init/Villages.java | 2 +- .../mc/steamadvantage/items/MusketItem.java | 196 ++++++++---------- .../machines/BlastFurnaceBlock.java | 10 +- .../machines/BlastFurnaceTileEntity.java | 38 ++-- .../machines/CoalBoilerBlock.java | 10 +- .../machines/CoalBoilerTileEntity.java | 24 +-- .../machines/ElectricBoilerBlock.java | 10 +- .../machines/ElectricBoilerTileEntity.java | 20 +- .../machines/GeothermalBoilerBlock.java | 10 +- .../machines/GeothermalBoilerTileEntity.java | 26 +-- .../machines/OilBoilerBlock.java | 10 +- .../machines/OilBoilerTileEntity.java | 24 +-- .../machines/RockCrusherBlock.java | 10 +- .../machines/RockCrusherTileEntity.java | 32 +-- .../machines/SteamDrillBlock.java | 46 ++-- .../machines/SteamDrillTileEntity.java | 106 +++++----- .../machines/SteamElevatorBlock.java | 10 +- .../machines/SteamElevatorTileEntity.java | 78 +++---- .../machines/SteamPumpBlock.java | 24 +-- .../machines/SteamPumpTileEntity.java | 54 ++--- .../machines/SteamStillBlock.java | 10 +- .../machines/SteamStillTileEntity.java | 18 +- .../machines/SteamTankBlock.java | 8 +- .../machines/SteamTankTileEntity.java | 4 +- .../migration/SteamLegacyMigrations.java | 8 +- .../recipe/RecipeConditions.java | 2 +- .../util/FurnaceFuelHelper.java | 12 +- .../mc/steamadvantage/util/SoundHelper.java | 24 +-- src/main/resources/META-INF/mods.toml | 4 +- src/main/resources/pack.mcmeta | 2 +- .../blocks/DrillBitPersistenceTest.java | 22 +- .../graphics/DrillBitRendererTest.java | 16 +- .../items/MusketPersistenceTest.java | 10 +- .../machines/SteamDrillPersistenceTest.java | 32 +-- .../machines/SteamMachinePersistenceTest.java | 146 +++++++++++++ .../migration/SteamLegacyMigrationsTest.java | 2 +- .../resources/BuildWorkflowContractTest.java | 12 +- .../resources/NativeBlockPropertiesTest.java | 44 ++-- .../resources/NativeFuelContractTest.java | 57 +++++ .../resources/NativeLootContractTest.java | 4 +- .../RecipeRegistrationThreadTest.java | 4 +- .../WorldOnlyConduitContractTest.java | 36 ++++ 76 files changed, 1050 insertions(+), 748 deletions(-) create mode 100644 src/test/java/zone/moddev/mc/steamadvantage/machines/SteamMachinePersistenceTest.java create mode 100644 src/test/java/zone/moddev/mc/steamadvantage/resources/NativeFuelContractTest.java create mode 100644 src/test/java/zone/moddev/mc/steamadvantage/resources/WorldOnlyConduitContractTest.java diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a7ab631..dc70ab1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,16 +1,16 @@ -name: Steam Advantage 1.15 CI +name: Steam 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: steamadvantage-1.15-${{ github.workflow }}-${{ github.ref }} + group: steamadvantage-1.16-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: @@ -21,11 +21,22 @@ jobs: steps: - name: Check out SteamAdvantage uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - name: Validate final Power source pin + shell: bash + run: | + set -euo pipefail + power_ref=$(sed -n 's/^poweradvantage_source_ref=//p' gradle.properties | tr -d '\r') + power_hash=$(sed -n 's/^poweradvantage_deobf_sha256=//p' gradle.properties | tr -d '\r') + if [[ ! "$power_ref" =~ ^[a-f0-9]{40}$ || ! "$power_hash" =~ ^[A-F0-9]{64}$ ]]; then + echo "::error::Final Power 1.16 dependency pin is pending." + exit 1 + fi + echo "POWERADVANTAGE_SOURCE_REF=$power_ref" >> "$GITHUB_ENV" - name: Check out pinned OreSpawn uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/OreSpawn - ref: 5613baf876747ed071cb7ad7e2aff4e0ce4f0a03 + ref: a113e5d767169189f0e35ade1e173a12d550b00e path: .ci-dependencies/OreSpawn - name: Use canonical LF dependency inputs # Use the same source bytes on hosted and local dependency builds. @@ -34,13 +45,13 @@ jobs: 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 + ref: 098d4625abc8a849bd1a11dcf697b3fee0cade7b path: .ci-dependencies/PowerAdvantage - name: Install pinned Java 25 Mavenizer runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 @@ -66,7 +77,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 +88,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 +111,20 @@ jobs: - name: Upload audited release candidate uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: SteamAdvantage-1.15.2-${{ github.sha }} + name: SteamAdvantage-1.16.5-${{ github.sha }} if-no-files-found: error retention-days: 30 path: | - build/libs/SteamAdvantage-2.2.7.115021.jar - build/libs/SteamAdvantage-2.2.7.115021-sources.jar - build/libs/SteamAdvantage-2.2.7.115021-javadoc.jar + build/libs/SteamAdvantage-2.2.8.116051.jar + build/libs/SteamAdvantage-2.2.8.116051-sources.jar + build/libs/SteamAdvantage-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: SteamAdvantage-1.15.2-diagnostics-${{ github.sha }} + name: SteamAdvantage-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 7a35df2..610b46b 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: '53 7 * * 4' @@ -21,11 +21,22 @@ jobs: steps: - name: Check out SteamAdvantage uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - name: Validate final Power source pin + shell: bash + run: | + set -euo pipefail + power_ref=$(sed -n 's/^poweradvantage_source_ref=//p' gradle.properties | tr -d '\r') + power_hash=$(sed -n 's/^poweradvantage_deobf_sha256=//p' gradle.properties | tr -d '\r') + if [[ ! "$power_ref" =~ ^[a-f0-9]{40}$ || ! "$power_hash" =~ ^[A-F0-9]{64}$ ]]; then + echo "::error::Final Power 1.16 dependency pin is pending." + exit 1 + fi + echo "POWERADVANTAGE_SOURCE_REF=$power_ref" >> "$GITHUB_ENV" - name: Check out pinned OreSpawn uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/OreSpawn - ref: 5613baf876747ed071cb7ad7e2aff4e0ce4f0a03 + ref: a113e5d767169189f0e35ade1e173a12d550b00e path: .ci-dependencies/OreSpawn - name: Use canonical LF dependency inputs # Use the same source bytes on hosted and local dependency builds. @@ -34,13 +45,13 @@ jobs: 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 + ref: 098d4625abc8a849bd1a11dcf697b3fee0cade7b path: .ci-dependencies/PowerAdvantage - name: Install pinned Java 25 Mavenizer runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 @@ -66,7 +77,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 +88,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 7fc6ea6..f4f685e 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,15 @@ +Steam Advantage 2.2.8.116051 (local port candidate) + +- Target Minecraft 1.16.5 / Forge 36.2.34 with official 1.16.5 mappings. +- Keep Java 8 compilation and runtime with ForgeGradle 7.0.34 / Gradle 9.6.1. +- Use world-only conduit callbacks and Power Advantage's native tile lifecycle. +- Adapt native NBT load/save, client model predicates, rendering and item attributes. +- Use queued setup and native Forge fuel calculation. +- Preserve registry identities, recipe and trade quantities, machine ratios and NBT. +- Retain exact track/platform opacity, collision and redstone behavior. +- Add exact native level, persistence and callback regressions. +- Pin Power's stable local API bootstrap; keep 1.16 runtime/manual qualification pending. + Steam Advantage 2.2.7.115021 - Target Minecraft 1.15.2 / Forge 31.2.57 with snapshot 20200514-1.15.1 mappings and MCP 20200515.085601. diff --git a/README.md b/README.md index aca7e9a..3b5d982 100644 --- a/README.md +++ b/README.md @@ -1,82 +1,87 @@ # SteamAdvantage -**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. The historical -[1.14 test results](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.14.4/docs/1.14/BROADER-QUALIFICATION.md) -are not evidence of 1.15 gameplay or world-upgrade compatibility. +**Minecraft 1.16.5 port candidate, version 2.2.8.116051.** +This branch is local work pending full verification and manual acceptance. +No 1.16 gameplay, rendering, or world-upgrade +qualification is claimed. Accepted 1.15 results do not qualify this candidate. -Steam Advantage adds steam-powered machines and infrastructure to Power Advantage for Minecraft 1.15.2. +Steam Advantage adds steam-powered machines and infrastructure to Power Advantage. -Every crafting 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). Regenerate unlock JSON after recipe changes with `node tools/generate-recipe-unlocks.js`; `check` audits recipe coverage and criteria. Crushing recipes are deliberately excluded from the crafting book. +## Build Target -The historical [manufacturing progression protocol](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.13.2/docs/1.13/MANUFACTURING-PROGRESSION.md) describes raw-material, processing and loot acquisition paths in every mode, including restart persistence. Earlier results do not establish those outcomes on 1.15. +The `master-1.16.5` target uses Minecraft 1.16.5, Forge 36.2.34, +official 1.16.5 mappings, and MCP config 20210115.111550. +ForgeGradle 7.0.34 and Gradle 9.6.1 run on Temurin 17.0.1+12. +Compilation and Minecraft launches use Temurin 8.0.502+7 and Java 8 bytecode; +Mavenizer uses Temurin 25.0.3+9.0.LTS. -## Building Minecraft 1.15.2 +Power Advantage 2.4.7.116051 remains a separate required mod. The stable local API +bootstrap B source is `098d4625abc8a849bd1a11dcf697b3fee0cade7b`; its development jar SHA-256 is +`78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3`. +These exact pins are recorded in `gradle.properties` and audited during builds. +Use an immutable development jar through `-PpowerAdvantageDeobfJar=`. +This API bootstrap is not runtime qualification and may be repinned after runtime +fixes. Release audits reject missing or placeholder pins. -The `master-1.15.2` build targets Forge 31.2.57, snapshot `20200514-1.15.1` mappings, -and MCP `20200515.085601`. It uses ForgeGradle 7.0.34 and Gradle 9.6.1. -Run Gradle with Temurin 17.0.1+12; production code is compiled with Temurin 8.0.502+7. -The Forge Mavenizer also requires Temurin 25.0.3+9.0.LTS. CI installs all three -explicitly and disables automatic toolchain detection and downloads. +Steam's 87-test build and artifact evidence belongs to bootstrap A, not B. +Bootstrap B initializes the GUI matrix before legacy direct decoration calls. +Steam compilation and the full suite against B remain pending the next cache +lease. Neither bootstrap has Steam runtime or manual acceptance. -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 a dependency from an earlier Minecraft version. -Base Metals `3.0.2.115021` source `ac1781e7cade15045ffe0135077087b4d1722603` -and Power source `6666099a734eba16561d98c86f3f4bb1b7c742f7` are the exact tested -dependency pins. CI builds them before Steam Advantage; none is embedded in -the Steam Advantage jar. +The supplied native development dependencies are Base Metals 3.1.1.116051 +(source `995f6cc4dd2d5eecc628a42e5c43fa5390c24bca`) and OreSpawn 4.1.0.116051 +(source `a113e5d767169189f0e35ade1e173a12d550b00e`). Their exact jar hashes +are recorded in `gradle.properties`. None of the dependencies is embedded. -With the standard sibling layout: +With matching native development jars available: ```text -cd ..\..\PowerAdvantage -gradlew.bat deobfJar +gradlew.bat compileJava compileTestJava -PpowerAdvantageDeobfJar= ``` -For local development, compile and run tests in SteamAdvantage: +Alternative layouts may also pass `-PbaseMetalsDeobfJar=` and +`-PoreSpawnDeobfJar=`. Explicit toolchain installations can be supplied +through Gradle project properties. Do not use a dependency from an older target. -```text -gradlew.bat compileJava test -``` - -With the exact Power dependency pinned, run the complete release gates: +With the exact dependency jars pinned, the full build 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. - -For Eclipse, import this repository as an existing Gradle project and run: - -```text -gradlew.bat cleanEclipse verifyEclipseProductionClasspath -``` - -Refresh the project in Eclipse, allow its Java build to finish, and launch the generated `runClient.launch`. Eclipse launches discover SteamAdvantage 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 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. +A compilation pass is not a test pass, release-audit pass, or runtime acceptance. +Shared Gradle caches require exclusive ownership; do not run competing builds +against the same cache or checkout. ## Compatibility -The 1.15 source adaptations retain machine callbacks, all six drill directions, native -helper-tile lifecycle, saved progress and target snapshots, energy/inventory NBT, legacy -fluid contracts, musket loaded-state bytes and migration codecs. Native villager professions -replace the removed smith careers (armorer, weaponsmith, toolsmith) and priest (cleric). -Trades retain their legacy level and price ranges; 1.14 restocking and profession selection -follow the native engine. - -Automated coverage is bounded to the recorded scenarios. It does not establish every -in-world GUI, rendering, sound, control or musket interaction, multiplayer behavior, -or compatibility with arbitrary third-party mods. Unit/resource tests alone are not -runtime or world-upgrade evidence. - -The combined 1.15 harness must be prepared before an all-Advantage play-test. Its launch and resource probe belong to the sibling PowerAdvantage checkout. The [historical resource-probe protocol](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.14.4/test-rig/client-resources/README.md) describes model, texture and name checks; its previous passes do not establish 1.15 rendering or gameplay results. - -The implementation namespace is `zone.moddev.mc.steamadvantage`. Runtime identities, registries, tile IDs, saved NBT, recipes, and assets remain stable. Steam registers its legacy state and NBT codecs with PowerAdvantage's shared migration hook so 1.10 and 1.12 worlds can be converted before Minecraft flattens old numeric block states. - -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; it is not a 1.15 migration qualification. Always make a whole-world backup before upgrading, keep the complete set of migration backups, and test only disposable copies. Check that every other mod supports the target version; these results do not qualify unrelated mods or an entire existing modpack. +Runtime identities remain `steamadvantage:*`; the implementation namespace remains +`zone.moddev.mc.steamadvantage`. Registry names, tile IDs, resources, recipes, +trade ranges, machine costs, output quantities, and persistent NBT remain stable. + +The native port uses world-only conduit callbacks. Power Advantage owns registry-key +dimension handling, shared capability invalidation/revival, fluid adapters, and base +tile lifecycle. Steam uses native `load(BlockState, CompoundNBT)` and +`save(CompoundNBT)`, retaining deferred drill targets, cached facing, progress, +inventory, energy, legacy tank aliases, and musket loaded-state bytes. +Saving a drill must not reacquire its world or neighbouring chunks. + +Client setup registers native item model predicates, drill rendering, and the +track's cutout layer. Native block predicates preserve non-occlusion and prevent +full-collision tracks and platforms from conducting redstone. Existing renderer +geometry, UVs, lighting, and animation axes are retained. + +Every crafting variant has ingredient-triggered recipe-book discovery. +Regenerate unlock JSON after recipe changes with +`node tools/generate-recipe-unlocks.js`. Processing recipes remain outside the +crafting book. Recipe conditions are registered on the queued setup thread. + +Unit tests cover native properties, exact levels and costs, persistence, +world-only callbacks, recipe discovery, and resources. They do not establish +in-world GUIs, sounds, interactions, multiplayer behavior, or arbitrary modpacks. + +Power Advantage supplies the combined-mod runtime harness and shared legacy +migration hook. Upgrade testing must use disposable whole-world copies with +pinned inputs. Preserve original worlds and backups; never open a world in an +older Minecraft version after upgrading it. Manual acceptance and publication +approval remain separate from automated evidence. diff --git a/build.gradle b/build.gradle index d6a77c8..65e4447 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: 'fmldatauserdev'] runs { configureEach { mainClass = 'net.minecraftforge.userdev.LaunchTesting' @@ -102,7 +102,7 @@ minecraft { systemProperty 'forge.logging.markers', 'REGISTRIES' systemProperty 'forge.logging.console.level', 'info' mods { steamadvantage { 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,12 +130,16 @@ 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 } tasks.withType(JavaExec).configureEach { + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(8) + vendor = JvmVendorSpec.ADOPTIUM + } if (name in ['runClient', 'runServer', 'runData']) { dependsOn prepareForgeRunModClasses } @@ -178,18 +182,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 +345,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 SteamAdvantage 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,24 +373,24 @@ 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_version != '2.4.7.116051' || project.poweradvantage_source_repository != 'MinecraftModDevelopmentMods/PowerAdvantage' - || !(project.poweradvantage_source_ref ==~ /[a-f0-9]{40}/) - || !(project.poweradvantage_deobf_sha256 ==~ /[A-F0-9]{64}/)) { + || project.poweradvantage_source_ref != '098d4625abc8a849bd1a11dcf697b3fee0cade7b' + || project.poweradvantage_deobf_sha256 != '78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3') { throw new GradleException('Unexpected PowerAdvantage compile dependency identity') } String mainSource = file( 'src/main/java/zone/moddev/mc/steamadvantage/SteamAdvantage.java').getText('UTF-8') if (!mainSource.contains('MODID = "steamadvantage"') - || !mainSource.contains('VERSION = "2.2.7.115021"')) { + || !mainSource.contains('VERSION = "2.2.8.116051"')) { throw new GradleException('SteamAdvantage source identity changed') } String metadata = file('src/main/resources/META-INF/mods.toml').getText('UTF-8').replace('\r\n', '\n') ['modId="steamadvantage"', '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}") } @@ -422,9 +426,9 @@ tasks.register('verifyReleaseDependencies') { if (manifest.getValue('Implementation-Version') != project.poweradvantage_version) { throw new GradleException('PowerAdvantage dependency manifest has the wrong version') } - if (manifest.getValue('Built-On') != '1.15.2-31.2.57' + if (manifest.getValue('Built-On') != '1.16.5-36.2.34' || manifest.getValue('Built-On-Java') != '8') { - throw new GradleException('PowerAdvantage must be the native 1.15.2 Java 8 dependency') + throw new GradleException('PowerAdvantage must be the native 1.16.5 Java 8 dependency') } } String actualBaseMetalsHash = MessageDigest.getInstance('SHA-256') @@ -525,8 +529,8 @@ tasks.register('verifyReleaseArtifacts') { } def resourcePack = new JsonSlurper().parseText(zip.getInputStream(zip.getEntry('pack.mcmeta')) .getText(StandardCharsets.UTF_8.name())) - if (resourcePack.pack.pack_format != 5) { - throw new GradleException('Packaged resources must use native 1.15 pack format 5') + if (resourcePack.pack.pack_format != 6) { + throw new GradleException('Packaged resources must use native 1.16 pack format 6') } ['agent-notes/', '.codex/', 'src/test/', 'fernflower_abstract_parameter_names.txt', 'cyano/poweradvantage/', diff --git a/gradle.properties b/gradle.properties index f28d4e6..594d478 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,14 +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_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 @@ -25,23 +26,25 @@ curseforge_project_id=240984 mod_id=steamadvantage mod_name=Steam Advantage mod_license=GPL-3.0-only -mod_version=2.2.7.115021 +mod_version=2.2.8.116051 mod_group=zone.moddev.mc.steamadvantage mod_authors=DrCyano mod_description=Steam-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 +# Bootstrap B: native GUI matrix initialization; Steam B verification is pending. +poweradvantage_source_ref=098d4625abc8a849bd1a11dcf697b3fee0cade7b +poweradvantage_deobf_sha256=78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3 -basemetals_version=3.0.2.115021 -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_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/steamadvantage/SteamAdvantage.java b/src/main/java/zone/moddev/mc/steamadvantage/SteamAdvantage.java index 3bbbe8e..5d04607 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/SteamAdvantage.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/SteamAdvantage.java @@ -30,12 +30,12 @@ import zone.moddev.mc.steamadvantage.migration.SteamLegacyMigrations; import zone.moddev.mc.steamadvantage.recipe.RecipeConditions; -/** Forge 1.15 entry point for Steam Advantage. */ +/** Forge 1.16 entry point for Steam Advantage. */ @Mod(SteamAdvantage.MODID) public final class SteamAdvantage { public static final String MODID = "steamadvantage"; public static final String NAME = "Steam 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 float MUSKET_DAMAGE = 20.0F; @@ -80,7 +80,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); SteamAdvantageConfig.apply(); Recipes.init(); TreasureChests.init(FMLPaths.CONFIGDIR.get()); diff --git a/src/main/java/zone/moddev/mc/steamadvantage/blocks/DrillBitBlock.java b/src/main/java/zone/moddev/mc/steamadvantage/blocks/DrillBitBlock.java index aa2b6d7..c489aed 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/blocks/DrillBitBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/blocks/DrillBitBlock.java @@ -13,7 +13,7 @@ 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; @@ -22,43 +22,43 @@ /** Hidden moving drill helper. It deliberately has no item form or drops. */ public class DrillBitBlock extends Block implements ITileEntityProvider { - private static final VoxelShape SHAPE = VoxelShapes.create(0.25D, 0.25D, 0.25D, 0.75D, 0.75D, 0.75D); + private static final VoxelShape SHAPE = VoxelShapes.box(0.25D, 0.25D, 0.25D, 0.75D, 0.75D, 0.75D); public DrillBitBlock() { - super(Block.Properties.create(Material.IRON).hardnessAndResistance(5.0F, 2000.0F).notSolid()); + super(Block.Properties.of(Material.METAL).strength(5.0F, 2000.0F).noOcclusion()); } - @Override public TileEntity createNewTileEntity(IBlockReader world) { return new DrillBitTileEntity(); } + @Override public TileEntity newBlockEntity(IBlockReader world) { return new DrillBitTileEntity(); } @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 List getDrops(BlockState state, LootContext.Builder context) { return Collections.emptyList(); } @Override - public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity victim) { - victim.attackEntityFrom(Power.machine_damage, 2.0F); + public void entityInside(BlockState state, World world, BlockPos pos, Entity victim) { + victim.hurt(Power.machine_damage, 2.0F); } @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()) { - TileEntity tile = world.getTileEntity(pos); - if (!world.isRemote && tile instanceof DrillBitTileEntity) { + TileEntity tile = world.getBlockEntity(pos); + if (!world.isClientSide && tile instanceof DrillBitTileEntity) { ((DrillBitTileEntity) tile).destroyLine(false); } } - super.onReplaced(state, world, pos, newState, moving); + super.onRemove(state, world, pos, newState, moving); } @Override - public void onExplosionDestroy(World world, BlockPos pos, Explosion explosion) { + public void wasExploded(World world, BlockPos pos, Explosion explosion) { destroyNeighbors(world, pos); - super.onExplosionDestroy(world, pos, explosion); + super.wasExploded(world, pos, explosion); } private void destroyNeighbors(World world, BlockPos pos) { - if (world.isRemote) return; + if (world.isClientSide) return; for (Direction side : Direction.values()) { - TileEntity tile = world.getTileEntity(pos.offset(side)); + TileEntity tile = world.getBlockEntity(pos.relative(side)); if (tile instanceof DrillBitTileEntity) ((DrillBitTileEntity) tile).destroyLine(); } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/blocks/DrillBitTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/blocks/DrillBitTileEntity.java index 9e8f89b..b0872e2 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/blocks/DrillBitTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/blocks/DrillBitTileEntity.java @@ -25,8 +25,8 @@ public DrillBitTileEntity(){ @Override public void tick(){ - if(hasWorld() && getWorld().isRemote){ - rotation = ROTATION_PER_TICK * (getWorld().getGameTime() % 20); + if(hasLevel() && getLevel().isClientSide){ + rotation = ROTATION_PER_TICK * (getLevel().getGameTime() % 20); } } public void setDirection(Direction dir){ @@ -40,8 +40,8 @@ public Direction.Axis getDirection(){ } public static void createDrillBitBlock(World w, BlockPos coord, Direction dir){ - w.setBlockState(coord, zone.moddev.mc.steamadvantage.init.Blocks.drillbit.getDefaultState()); - TileEntity tile = w.getTileEntity(coord); + w.setBlockAndUpdate(coord, zone.moddev.mc.steamadvantage.init.Blocks.drillbit.defaultBlockState()); + TileEntity tile = w.getBlockEntity(coord); if(tile instanceof DrillBitTileEntity) ((DrillBitTileEntity) tile).setDirection(dir); } @@ -53,45 +53,45 @@ public void destroyLine(){ } public void destroyLine(boolean removeOrigin){ - if(!hasWorld() || getWorld().isRemote) return; + if(!hasLevel() || getLevel().isClientSide) return; List line = new ArrayList<>(); - line.add(getPos()); + line.add(getBlockPos()); collectLine(line, direction); collectLine(line, direction.getOpposite()); // Detach all helpers before block replacement callbacks can re-enter this line. - for(BlockPos coord : line) getWorld().removeTileEntity(coord); + for(BlockPos coord : line) getLevel().removeBlockEntity(coord); for(BlockPos coord : line) { - if(removeOrigin || !coord.equals(getPos())) getWorld().removeBlock(coord, false); + if(removeOrigin || !coord.equals(getBlockPos())) getLevel().removeBlock(coord, false); } } /** * destroys upstream drillbit */ private void collectLine(List line, Direction f){ - BlockPos coord = this.getPos().offset(f); - while(getWorld().isBlockLoaded(coord) && getWorld().getBlockState(coord).getBlock() == Blocks.drillbit){ + BlockPos coord = this.getBlockPos().relative(f); + while(getLevel().hasChunkAt(coord) && getLevel().getBlockState(coord).getBlock() == Blocks.drillbit){ line.add(coord); - coord = coord.offset(f); + coord = coord.relative(f); } } @Override - public CompoundNBT write(CompoundNBT root){ - super.write(root); + public CompoundNBT save(CompoundNBT root){ + super.save(root); writeDirectionToNBT(root); return root; } @Override - public void read(CompoundNBT root){ - super.read(root); + public void load(net.minecraft.block.BlockState state, CompoundNBT root){ + super.load(state, root); readDirectionFromNBT(root); } @Override public CompoundNBT getUpdateTag() { - return write(new CompoundNBT()); + return save(new CompoundNBT()); } /** @@ -101,18 +101,18 @@ public CompoundNBT getUpdateTag() { public SUpdateTileEntityPacket getUpdatePacket(){ CompoundNBT nbtTag = new CompoundNBT(); writeDirectionToNBT(nbtTag); - return new SUpdateTileEntityPacket(this.getPos(), 0, nbtTag); + return new SUpdateTileEntityPacket(this.getBlockPos(), 0, nbtTag); } /** * Receives the network packet made by getDescriptionPacket() */ @Override public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket packet) { - readDirectionFromNBT(packet.getNbtCompound()); + readDirectionFromNBT(packet.getTag()); } private void writeDirectionToNBT(CompoundNBT root) { - root.putByte("dir", (byte)direction.getIndex()); + root.putByte("dir", (byte)direction.get3DDataValue()); } private void readDirectionFromNBT(CompoundNBT root) { @@ -124,14 +124,14 @@ private void readDirectionFromNBT(CompoundNBT root) { } private static Direction decodeDirection(int index) { - return index >= 0 && index < Direction.values().length ? Direction.byIndex(index) : Direction.DOWN; + return index >= 0 && index < Direction.values().length ? Direction.from3DDataValue(index) : Direction.DOWN; } private void syncDirection() { - if(hasWorld() && !getWorld().isRemote) { - markDirty(); - BlockState state = getWorld().getBlockState(getPos()); - getWorld().notifyBlockUpdate(getPos(), state, state, 3); + if(hasLevel() && !getLevel().isClientSide) { + setChanged(); + BlockState state = getLevel().getBlockState(getBlockPos()); + getLevel().sendBlockUpdated(getBlockPos(), state, state, 3); } } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/blocks/PlatformBlock.java b/src/main/java/zone/moddev/mc/steamadvantage/blocks/PlatformBlock.java index 07c7add..383603d 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/blocks/PlatformBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/blocks/PlatformBlock.java @@ -12,7 +12,7 @@ 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.IBlockReader; import net.minecraft.world.World; import zone.moddev.mc.steamadvantage.init.Blocks; @@ -21,22 +21,24 @@ public class PlatformBlock extends Block { public static final IntegerProperty HEIGHT = IntegerProperty.create("height", 0, 4); private static final VoxelShape[] SHAPES = new VoxelShape[] { - VoxelShapes.create(0.25D, 0.0D, 0.25D, 0.75D, 1.0D, 0.75D), - VoxelShapes.create(0.0D, 0.0D, 0.0D, 1.0D, 0.25D, 1.0D), - VoxelShapes.create(0.0D, 0.0D, 0.0D, 1.0D, 0.50D, 1.0D), - VoxelShapes.create(0.0D, 0.0D, 0.0D, 1.0D, 0.75D, 1.0D), - VoxelShapes.fullCube() + VoxelShapes.box(0.25D, 0.0D, 0.25D, 0.75D, 1.0D, 0.75D), + VoxelShapes.box(0.0D, 0.0D, 0.0D, 1.0D, 0.25D, 1.0D), + VoxelShapes.box(0.0D, 0.0D, 0.0D, 1.0D, 0.50D, 1.0D), + VoxelShapes.box(0.0D, 0.0D, 0.0D, 1.0D, 0.75D, 1.0D), + VoxelShapes.block() }; public PlatformBlock() { - super(Block.Properties.create(Material.IRON).hardnessAndResistance(5.0F, 2000.0F).notSolid()); - setDefaultState(getStateContainer().getBaseState().with(HEIGHT, 1)); + super(Block.Properties.of(Material.METAL).strength(5.0F, 2000.0F).noOcclusion() + .isRedstoneConductor((state, world, pos) -> false) + .isSuffocating((state, world, pos) -> false) + .isViewBlocking((state, world, pos) -> false)); + registerDefaultState(getStateDefinition().any().setValue(HEIGHT, 1)); } - @Override protected void fillStateContainer(StateContainer.Builder builder) { builder.add(HEIGHT); } - @Override public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) { return SHAPES[state.get(HEIGHT)]; } - @Override public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) { return SHAPES[state.get(HEIGHT)]; } - @Override public boolean isNormalCube(BlockState state, IBlockReader world, BlockPos pos) { return false; } + @Override protected void createBlockStateDefinition(StateContainer.Builder builder) { builder.add(HEIGHT); } + @Override public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) { return SHAPES[state.getValue(HEIGHT)]; } + @Override public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) { return SHAPES[state.getValue(HEIGHT)]; } @Override public List getDrops(BlockState state, LootContext.Builder context) { return Collections.emptyList(); } @Override @@ -45,7 +47,7 @@ public void neighborChanged(BlockState state, World world, BlockPos pos, Block b } public boolean canBlockStay(World world, BlockPos pos) { - Block below = world.getBlockState(pos.down()).getBlock(); + Block below = world.getBlockState(pos.below()).getBlock(); return below == this || below == Blocks.steam_elevator_platform || below == Blocks.steam_elevator; } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/blocks/PumpPipeBlock.java b/src/main/java/zone/moddev/mc/steamadvantage/blocks/PumpPipeBlock.java index 3a0fb9f..52a6654 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/blocks/PumpPipeBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/blocks/PumpPipeBlock.java @@ -10,17 +10,17 @@ 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 pipe shaft placed beneath a steam pump. */ public class PumpPipeBlock extends Block { - private static final VoxelShape SHAPE = VoxelShapes.create(0.0D, 0.25D, 0.0D, 0.75D, 1.0D, 1.0D); + private static final VoxelShape SHAPE = VoxelShapes.box(0.0D, 0.25D, 0.0D, 0.75D, 1.0D, 1.0D); public PumpPipeBlock() { - super(Block.Properties.create(Material.IRON).hardnessAndResistance(5.0F, 10.0F).notSolid()); + super(Block.Properties.of(Material.METAL).strength(5.0F, 10.0F).noOcclusion()); } @Override public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) { return SHAPE; } @@ -28,23 +28,23 @@ public PumpPipeBlock() { @Override public List getDrops(BlockState state, LootContext.Builder context) { return 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()) destroyShaft(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) { + public void wasExploded(World world, BlockPos pos, Explosion explosion) { destroyShaft(world, pos); - super.onExplosionDestroy(world, pos, explosion); + super.wasExploded(world, pos, explosion); } private void destroyShaft(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.destroyBlock(cursor, false); - cursor = cursor.down(); + cursor = cursor.below(); } } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/blocks/SteamTrackBlock.java b/src/main/java/zone/moddev/mc/steamadvantage/blocks/SteamTrackBlock.java index 7a3ff6b..7037ecf 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/blocks/SteamTrackBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/blocks/SteamTrackBlock.java @@ -12,10 +12,12 @@ public class SteamTrackBlock extends BlockSimplePowerConduit { public SteamTrackBlock() { - super(Properties.create(Material.PISTON).hardnessAndResistance(0.75F).notSolid(), + super(Properties.of(Material.PISTON).strength(0.75F).noOcclusion() + .isRedstoneConductor((state, world, pos) -> false) + .isSuffocating((state, world, pos) -> false) + .isViewBlocking((state, world, pos) -> false), 2.0F / 16.0F, Power.steam_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/steamadvantage/compat/BaseMetalsCompat.java b/src/main/java/zone/moddev/mc/steamadvantage/compat/BaseMetalsCompat.java index af63216..591ff4e 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/compat/BaseMetalsCompat.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/compat/BaseMetalsCompat.java @@ -29,10 +29,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 && candidate.matches(inventory, world)) { - return candidate.getRecipeOutput().copy(); + return candidate.getResultItem().copy(); } } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/enchantments/HighExplosiveEnchantment.java b/src/main/java/zone/moddev/mc/steamadvantage/enchantments/HighExplosiveEnchantment.java index 6adee66..57593c0 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/enchantments/HighExplosiveEnchantment.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/enchantments/HighExplosiveEnchantment.java @@ -8,29 +8,29 @@ public class HighExplosiveEnchantment extends net.minecraft.enchantment.Enchantment{ public HighExplosiveEnchantment() { - super(Rarity.UNCOMMON,EnchantmentType.ALL,new EquipmentSlotType[]{EquipmentSlotType.MAINHAND}); + super(Rarity.UNCOMMON,EnchantmentType.BREAKABLE,new EquipmentSlotType[]{EquipmentSlotType.MAINHAND}); } @Override - public boolean canApply(ItemStack item){ + public boolean canEnchant(ItemStack item){ return item.getItem() == Items.blackpowder_musket; } @Override public boolean canApplyAtEnchantingTable(ItemStack item){ - return canApply(item); + return canEnchant(item); } @Override - public int getMinEnchantability(final int lvl) { + public int getMinCost(final int lvl) { return lvl * 7; } @Override - public int getMaxEnchantability(final int lvl) { - return this.getMinEnchantability(lvl) + 10; + public int getMaxCost(final int lvl) { + return this.getMinCost(lvl) + 10; } @Override diff --git a/src/main/java/zone/moddev/mc/steamadvantage/enchantments/PowderlessEnchantment.java b/src/main/java/zone/moddev/mc/steamadvantage/enchantments/PowderlessEnchantment.java index 307e77a..6afd069 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/enchantments/PowderlessEnchantment.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/enchantments/PowderlessEnchantment.java @@ -8,28 +8,28 @@ public class PowderlessEnchantment extends net.minecraft.enchantment.Enchantment{ public PowderlessEnchantment() { - super(Rarity.VERY_RARE,EnchantmentType.ALL,new EquipmentSlotType[]{EquipmentSlotType.MAINHAND}); + super(Rarity.VERY_RARE,EnchantmentType.BREAKABLE,new EquipmentSlotType[]{EquipmentSlotType.MAINHAND}); } @Override - public boolean canApply(ItemStack item){ + public boolean canEnchant(ItemStack item){ return item.getItem() == Items.blackpowder_musket; } @Override public boolean canApplyAtEnchantingTable(ItemStack item){ - return canApply(item); + return canEnchant(item); } @Override - public int getMinEnchantability(final int lvl) { + public int getMinCost(final int lvl) { return 20; } @Override - public int getMaxEnchantability(final int lvl) { + public int getMaxCost(final int lvl) { return 50; } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/enchantments/RapidReloadEnchantment.java b/src/main/java/zone/moddev/mc/steamadvantage/enchantments/RapidReloadEnchantment.java index 7f0a89e..6e560c1 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/enchantments/RapidReloadEnchantment.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/enchantments/RapidReloadEnchantment.java @@ -8,28 +8,28 @@ public class RapidReloadEnchantment extends net.minecraft.enchantment.Enchantment{ public RapidReloadEnchantment() { - super(Rarity.RARE,EnchantmentType.ALL,new EquipmentSlotType[]{EquipmentSlotType.MAINHAND}); + super(Rarity.RARE,EnchantmentType.BREAKABLE,new EquipmentSlotType[]{EquipmentSlotType.MAINHAND}); } @Override - public boolean canApply(ItemStack item){ + public boolean canEnchant(ItemStack item){ return item.getItem() == Items.blackpowder_musket; } @Override public boolean canApplyAtEnchantingTable(ItemStack item){ - return canApply(item); + return canEnchant(item); } @Override - public int getMinEnchantability(final int lvl) { + public int getMinCost(final int lvl) { return 15; } @Override - public int getMaxEnchantability(final int lvl) { + public int getMaxCost(final int lvl) { return 50; } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/enchantments/RecoilEnchantment.java b/src/main/java/zone/moddev/mc/steamadvantage/enchantments/RecoilEnchantment.java index d0a2614..4f666a5 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/enchantments/RecoilEnchantment.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/enchantments/RecoilEnchantment.java @@ -8,29 +8,29 @@ public class RecoilEnchantment extends net.minecraft.enchantment.Enchantment{ public RecoilEnchantment() { - super(Rarity.COMMON,EnchantmentType.ALL,new EquipmentSlotType[]{EquipmentSlotType.MAINHAND}); + super(Rarity.COMMON,EnchantmentType.BREAKABLE,new EquipmentSlotType[]{EquipmentSlotType.MAINHAND}); } @Override - public boolean canApply(ItemStack item){ + public boolean canEnchant(ItemStack item){ return item.getItem() == Items.blackpowder_musket; } @Override public boolean canApplyAtEnchantingTable(ItemStack item){ - return canApply(item); + return canEnchant(item); } @Override - public int getMinEnchantability(final int lvl) { + public int getMinCost(final int lvl) { return Math.max(1,lvl * 5 - 3); } @Override - public int getMaxEnchantability(final int lvl) { - return this.getMinEnchantability(lvl) + 10; + public int getMaxCost(final int lvl) { + return this.getMinCost(lvl) + 10; } @Override diff --git a/src/main/java/zone/moddev/mc/steamadvantage/graphics/ClientRegistration.java b/src/main/java/zone/moddev/mc/steamadvantage/graphics/ClientRegistration.java index 1f43107..0fd41de 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/graphics/ClientRegistration.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/graphics/ClientRegistration.java @@ -4,6 +4,10 @@ import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderTypeLookup; +import net.minecraft.item.ItemModelsProperties; +import net.minecraft.util.ResourceLocation; +import zone.moddev.mc.steamadvantage.init.Items; +import zone.moddev.mc.steamadvantage.items.MusketItem; import zone.moddev.mc.steamadvantage.init.Blocks; import zone.moddev.mc.steamadvantage.init.Entities; @@ -12,7 +16,14 @@ public final class ClientRegistration { private ClientRegistration() {} public static void onClientSetup(FMLClientSetupEvent event) { - ClientRegistry.bindTileEntityRenderer(Entities.DRILLBIT, DrillBitRenderer::new); - RenderTypeLookup.setRenderLayer(Blocks.steam_track, RenderType.getCutout()); + event.enqueueWork(() -> { + ClientRegistry.bindTileEntityRenderer(Entities.DRILLBIT, DrillBitRenderer::new); + RenderTypeLookup.setRenderLayer(Blocks.steam_track, RenderType.cutout()); + ItemModelsProperties.register(Items.blackpowder_musket, new ResourceLocation("loaded"), + (item, world, entity) -> MusketItem.isLoaded(item) ? 1.0F : 0.0F); + ItemModelsProperties.register(Items.blackpowder_musket, new ResourceLocation("loading"), + (item, world, entity) -> entity != null && entity.isUsingItem() + && entity.getUseItem() == item ? 1.0F : 0.0F); + }); } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/graphics/DrillBitRenderer.java b/src/main/java/zone/moddev/mc/steamadvantage/graphics/DrillBitRenderer.java index 5024790..eaf2a4f 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/graphics/DrillBitRenderer.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/graphics/DrillBitRenderer.java @@ -4,7 +4,7 @@ import com.mojang.blaze3d.vertex.IVertexBuilder; 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; @@ -27,20 +27,20 @@ public DrillBitRenderer(TileEntityRendererDispatcher dispatcher) { public void render(DrillBitTileEntity tile, float partialTick, MatrixStack matrices, IRenderTypeBuffer buffers, int light, int overlay) { renderGeometry(tile.getDirection(), tile.rotation + DrillBitTileEntity.ROTATION_PER_TICK * partialTick, - matrices, buffers.getBuffer(RenderType.getEntityTranslucent(TEXTURE)), light, overlay); + matrices, buffers.getBuffer(RenderType.entityTranslucent(TEXTURE)), light, overlay); } static void renderGeometry(Direction.Axis axis, float rotation, MatrixStack matrices, IVertexBuilder vertices, int light, int overlay) { - matrices.push(); + matrices.pushPose(); try { matrices.translate(0.5D, 0.5D, 0.5D); if (axis != Direction.Axis.Y) { - matrices.rotate(Vector3f.XP.rotationDegrees(90.0F)); - if (axis != Direction.Axis.Z) matrices.rotate(Vector3f.ZP.rotationDegrees(90.0F)); + matrices.mulPose(Vector3f.XP.rotationDegrees(90.0F)); + if (axis != Direction.Axis.Z) matrices.mulPose(Vector3f.ZP.rotationDegrees(90.0F)); } - matrices.rotate(Vector3f.YP.rotationDegrees(rotation)); - MatrixStack.Entry transform = matrices.getLast(); + matrices.mulPose(Vector3f.YP.rotationDegrees(rotation)); + MatrixStack.Entry transform = matrices.last(); final float radius = 0.25F; // Retain the original six quads and UV layout; native buffers supply lighting and overlay. vertex(transform, vertices, radius, 0.5F, -radius, 0, 0, 0, 0, -1, light, overlay); @@ -73,15 +73,15 @@ static void renderGeometry(Direction.Axis axis, float rotation, MatrixStack matr vertex(transform, vertices, radius, -0.5F, -radius, 1, 0.5F, 0, -1, 0, light, overlay); vertex(transform, vertices, radius, -0.5F, radius, 1, 0, 0, -1, 0, light, overlay); } finally { - matrices.pop(); + matrices.popPose(); } } private static void vertex(MatrixStack.Entry transform, IVertexBuilder vertices, float x, float y, float z, float u, float v, float normalX, float normalY, float normalZ, int light, int overlay) { - vertices.pos(transform.getMatrix(), x, y, z).color(255, 255, 255, 255).tex(u, v) - .overlay(overlay).lightmap(light) - .normal(transform.getNormal(), normalX, normalY, normalZ).endVertex(); + vertices.vertex(transform.pose(), x, y, z).color(255, 255, 255, 255).uv(u, v) + .overlayCoords(overlay).uv2(light) + .normal(transform.normal(), normalX, normalY, normalZ).endVertex(); } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/gui/BlastFurnaceGUI.java b/src/main/java/zone/moddev/mc/steamadvantage/gui/BlastFurnaceGUI.java index 24dd0ea..78e8d9a 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/gui/BlastFurnaceGUI.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/gui/BlastFurnaceGUI.java @@ -21,11 +21,11 @@ public BlastFurnaceGUI() { @Override public ItemStack onTake(PlayerEntity player, ItemStack stack) { - stack.onCrafting(player.getEntityWorld(), player, stack.getCount()); + stack.onCraftedBy(player.level, player, stack.getCount()); return super.onTake(player, stack); } @Override - public boolean isItemValid(ItemStack stack){ return false; } + public boolean mayPlace(ItemStack stack){ return false; } }); } @@ -47,7 +47,7 @@ public ItemStack onTake(PlayerEntity player, ItemStack stack) * @param guiContainer This is the instance of GUIContainer that is drawing * the GUI. You need to use it to draw on the screen. For example:
-net.minecraft.client.Minecraft.getInstance().getTextureManager().bindTexture(arrowTexture);
+net.minecraft.client.Minecraft.getInstance().getTextureManager().bind(arrowTexture);
 guiContainer.blit(x+79, y+35, 0, 0, arrowLength, 17); // x, y, textureOffsetX, textureOffsetY, width, height)
 	   
* @param x This is the x coordinate (in pixels) from the top-left corner of diff --git a/src/main/java/zone/moddev/mc/steamadvantage/gui/CoalBoilerGUI.java b/src/main/java/zone/moddev/mc/steamadvantage/gui/CoalBoilerGUI.java index 6391db8..f561885 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/gui/CoalBoilerGUI.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/gui/CoalBoilerGUI.java @@ -34,7 +34,7 @@ public CoalBoilerGUI() { * @param guiContainer This is the instance of GUIContainer that is drawing * the GUI. You need to use it to draw on the screen. For example:
-net.minecraft.client.Minecraft.getInstance().getTextureManager().bindTexture(arrowTexture);
+net.minecraft.client.Minecraft.getInstance().getTextureManager().bind(arrowTexture);
 guiContainer.blit(x+79, y+35, 0, 0, arrowLength, 17); // x, y, textureOffsetX, textureOffsetY, width, height)
 	   
* @param x This is the x coordinate (in pixels) from the top-left corner of diff --git a/src/main/java/zone/moddev/mc/steamadvantage/gui/ElectricBoilerGUI.java b/src/main/java/zone/moddev/mc/steamadvantage/gui/ElectricBoilerGUI.java index 2523589..6794718 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/gui/ElectricBoilerGUI.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/gui/ElectricBoilerGUI.java @@ -34,7 +34,7 @@ public ElectricBoilerGUI() { * @param guiContainer This is the instance of GUIContainer that is drawing * the GUI. You need to use it to draw on the screen. For example:
-net.minecraft.client.Minecraft.getInstance().getTextureManager().bindTexture(arrowTexture);
+net.minecraft.client.Minecraft.getInstance().getTextureManager().bind(arrowTexture);
 guiContainer.blit(x+79, y+35, 0, 0, arrowLength, 17); // x, y, textureOffsetX, textureOffsetY, width, height)
 	   
* @param x This is the x coordinate (in pixels) from the top-left corner of diff --git a/src/main/java/zone/moddev/mc/steamadvantage/gui/GUIHelper.java b/src/main/java/zone/moddev/mc/steamadvantage/gui/GUIHelper.java index 81c9109..faebeec 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/gui/GUIHelper.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/gui/GUIHelper.java @@ -40,7 +40,7 @@ public static void drawNeedle(float pivotX, float pivotY, float zLevel, float angle = (1f - value) * PI; float offsetX = pivotX; float offsetY = pivotY; - BufferBuilder renderer = Tessellator.getInstance().getBuffer(); + BufferBuilder renderer = Tessellator.getInstance().getBuilder(); float sin = MathHelper.sin(angle); float cos = MathHelper.cos(angle); @@ -78,9 +78,9 @@ public static void drawNeedle(float pivotX, float pivotY, float zLevel, // (x, y, z, u, v) for(int i = 3; i >= 0; i--){ - renderer.pos(x[i], y[i], zLevel).tex(u[i],v[i]).endVertex();; + renderer.vertex(x[i], y[i], zLevel).uv(u[i],v[i]).endVertex();; } - net.minecraft.client.renderer.Tessellator.getInstance().draw(); + net.minecraft.client.renderer.Tessellator.getInstance().end(); } @@ -108,7 +108,7 @@ public static void drawFluidBar(FluidStack fs, float barHeight, int xPos, int yP if(barHeight > 0){ FluidTankGUI.drawFluidFilledRectangle(guiContainer,fs,x+xPos, y+yPos+barSlotHeight-h,w, h,z); } - net.minecraft.client.Minecraft.getInstance().getTextureManager().bindTexture(displayImage); + net.minecraft.client.Minecraft.getInstance().getTextureManager().bind(displayImage); guiContainer.blit(x+xPos-texMarginW, y+yPos-texMarginH, texOverlayX, texOverlayY, texOverlayW, texOverlayH); // x, y, textureOffsetX, textureOffsetY, width, height) } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/gui/GeothermalBoilerGUI.java b/src/main/java/zone/moddev/mc/steamadvantage/gui/GeothermalBoilerGUI.java index e9a12d7..4443823 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/gui/GeothermalBoilerGUI.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/gui/GeothermalBoilerGUI.java @@ -34,7 +34,7 @@ public GeothermalBoilerGUI() { * @param guiContainer This is the instance of GUIContainer that is drawing * the GUI. You need to use it to draw on the screen. For example:
-net.minecraft.client.Minecraft.getInstance().getTextureManager().bindTexture(arrowTexture);
+net.minecraft.client.Minecraft.getInstance().getTextureManager().bind(arrowTexture);
 guiContainer.blit(x+79, y+35, 0, 0, arrowLength, 17); // x, y, textureOffsetX, textureOffsetY, width, height)
 	   
* @param x This is the x coordinate (in pixels) from the top-left corner of diff --git a/src/main/java/zone/moddev/mc/steamadvantage/gui/OilBoilerGUI.java b/src/main/java/zone/moddev/mc/steamadvantage/gui/OilBoilerGUI.java index b31d60d..13347ef 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/gui/OilBoilerGUI.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/gui/OilBoilerGUI.java @@ -34,7 +34,7 @@ public OilBoilerGUI() { * @param guiContainer This is the instance of GUIContainer that is drawing * the GUI. You need to use it to draw on the screen. For example:
-net.minecraft.client.Minecraft.getInstance().getTextureManager().bindTexture(arrowTexture);
+net.minecraft.client.Minecraft.getInstance().getTextureManager().bind(arrowTexture);
 guiContainer.blit(x+79, y+35, 0, 0, arrowLength, 17); // x, y, textureOffsetX, textureOffsetY, width, height)
 	   
* @param x This is the x coordinate (in pixels) from the top-left corner of diff --git a/src/main/java/zone/moddev/mc/steamadvantage/gui/RockCrusherGUI.java b/src/main/java/zone/moddev/mc/steamadvantage/gui/RockCrusherGUI.java index aaf4521..2bf5e53 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/gui/RockCrusherGUI.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/gui/RockCrusherGUI.java @@ -33,7 +33,7 @@ public RockCrusherGUI() { * @param guiContainer This is the instance of GUIContainer that is drawing * the GUI. You need to use it to draw on the screen. For example:
-net.minecraft.client.Minecraft.getInstance().getTextureManager().bindTexture(arrowTexture);
+net.minecraft.client.Minecraft.getInstance().getTextureManager().bind(arrowTexture);
 guiContainer.blit(x+79, y+35, 0, 0, arrowLength, 17); // x, y, textureOffsetX, textureOffsetY, width, height)
 	   
* @param x This is the x coordinate (in pixels) from the top-left corner of diff --git a/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamDrillGUI.java b/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamDrillGUI.java index d2b819e..ce7811d 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamDrillGUI.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamDrillGUI.java @@ -33,7 +33,7 @@ public SteamDrillGUI() { * @param guiContainer This is the instance of GUIContainer that is drawing * the GUI. You need to use it to draw on the screen. For example:
-net.minecraft.client.Minecraft.getInstance().getTextureManager().bindTexture(arrowTexture);
+net.minecraft.client.Minecraft.getInstance().getTextureManager().bind(arrowTexture);
 guiContainer.blit(x+79, y+35, 0, 0, arrowLength, 17); // x, y, textureOffsetX, textureOffsetY, width, height)
 	   
* @param x This is the x coordinate (in pixels) from the top-left corner of diff --git a/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamPumpGUI.java b/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamPumpGUI.java index 7cc893c..26f0595 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamPumpGUI.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamPumpGUI.java @@ -34,7 +34,7 @@ public SteamPumpGUI() { * @param guiContainer This is the instance of GUIContainer that is drawing * the GUI. You need to use it to draw on the screen. For example:
-net.minecraft.client.Minecraft.getInstance().getTextureManager().bindTexture(arrowTexture);
+net.minecraft.client.Minecraft.getInstance().getTextureManager().bind(arrowTexture);
 guiContainer.blit(x+79, y+35, 0, 0, arrowLength, 17); // x, y, textureOffsetX, textureOffsetY, width, height)
 	   
* @param x This is the x coordinate (in pixels) from the top-left corner of diff --git a/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamStillGUI.java b/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamStillGUI.java index 6a509c5..89961ec 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamStillGUI.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamStillGUI.java @@ -34,7 +34,7 @@ public SteamStillGUI() { * @param guiContainer This is the instance of GUIContainer that is drawing * the GUI. You need to use it to draw on the screen. For example:
-net.minecraft.client.Minecraft.getInstance().getTextureManager().bindTexture(arrowTexture);
+net.minecraft.client.Minecraft.getInstance().getTextureManager().bind(arrowTexture);
 guiContainer.blit(x+79, y+35, 0, 0, arrowLength, 17); // x, y, textureOffsetX, textureOffsetY, width, height)
 	   
* @param x This is the x coordinate (in pixels) from the top-left corner of diff --git a/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamTankGUI.java b/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamTankGUI.java index 0f36084..46bc447 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamTankGUI.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/gui/SteamTankGUI.java @@ -33,7 +33,7 @@ public SteamTankGUI() { * @param guiContainer This is the instance of GUIContainer that is drawing * the GUI. You need to use it to draw on the screen. For example:
-net.minecraft.client.Minecraft.getInstance().getTextureManager().bindTexture(arrowTexture);
+net.minecraft.client.Minecraft.getInstance().getTextureManager().bind(arrowTexture);
 guiContainer.blit(x+79, y+35, 0, 0, arrowLength, 17); // x, y, textureOffsetX, textureOffsetY, width, height)
 	   
* @param x This is the x coordinate (in pixels) from the top-left corner of diff --git a/src/main/java/zone/moddev/mc/steamadvantage/init/Blocks.java b/src/main/java/zone/moddev/mc/steamadvantage/init/Blocks.java index affa95d..8cec5d5 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/init/Blocks.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/init/Blocks.java @@ -73,7 +73,7 @@ public static synchronized void init() { steam_elevator_platform = add(new PlatformBlock(), "platform"); steam_elevator_platforms = new BlockState[5]; for (int i = 0; i < steam_elevator_platforms.length; i++) { - steam_elevator_platforms[i] = steam_elevator_platform.getDefaultState().with(PlatformBlock.HEIGHT, i); + steam_elevator_platforms[i] = steam_elevator_platform.defaultBlockState().setValue(PlatformBlock.HEIGHT, i); } steam_elevator = (GUIBlock) add(new SteamElevatorBlock(), "steam_elevator"); steam_switch = add(new BlockPowerSwitch(Power.steam_power), "steam_switch"); @@ -102,7 +102,7 @@ public static void registerBlockItems(RegistryEvent.Register event) { for (Map.Entry entry : ALL_BLOCKS.entrySet()) { Item.Properties properties = new Item.Properties(); if (!"pump_pipe_steam".equals(entry.getKey()) && !"drillbit".equals(entry.getKey())) { - properties.group(ItemGroups.tab_powerAdvantage); + properties.tab(ItemGroups.tab_powerAdvantage); } BlockItem item = new BlockItem(entry.getValue(), properties); item.setRegistryName(SteamAdvantage.MODID, entry.getKey()); diff --git a/src/main/java/zone/moddev/mc/steamadvantage/init/Entities.java b/src/main/java/zone/moddev/mc/steamadvantage/init/Entities.java index 1661127..0f26c0f 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/init/Entities.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/init/Entities.java @@ -59,7 +59,7 @@ public static void register(RegistryEvent.Register> event) { private static TileEntityType register( RegistryEvent.Register> event, String id, Supplier factory, Block block) { - TileEntityType type = TileEntityType.Builder.create(factory, block).build(null); + TileEntityType type = TileEntityType.Builder.of(factory, block).build(null); type.setRegistryName(SteamAdvantage.MODID, id); event.getRegistry().register(type); return type; diff --git a/src/main/java/zone/moddev/mc/steamadvantage/init/Items.java b/src/main/java/zone/moddev/mc/steamadvantage/init/Items.java index 05c66c6..360f796 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/init/Items.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/init/Items.java @@ -29,12 +29,12 @@ public static synchronized void init() { steam_governor = add("steam_governor", new Item(properties())); steam_drill_bit = add("steam_drill_bit", new Item(properties())); blackpowder_cartridge = add("blackpowder_cartridge", new Item(properties())); - blackpowder_musket = add("musket", new MusketItem(properties().maxStackSize(1))); + blackpowder_musket = add("musket", new MusketItem(properties().stacksTo(1))); initialized = true; } private static Item.Properties properties() { - return new Item.Properties().group(ItemGroups.tab_powerAdvantage); + return new Item.Properties().tab(ItemGroups.tab_powerAdvantage); } private static Item add(String id, Item item) { diff --git a/src/main/java/zone/moddev/mc/steamadvantage/init/Villages.java b/src/main/java/zone/moddev/mc/steamadvantage/init/Villages.java index d17d8d8..22e12cd 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/init/Villages.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/init/Villages.java @@ -35,7 +35,7 @@ public static void addTrades(VillagerTradesEvent event) { if (profession == VillagerProfession.CLERIC) { event.getTrades().get(3).add((trader, random) -> { int enchantmentLevel = 5 + random.nextInt(15); - ItemStack musket = EnchantmentHelper.addRandomEnchantment(random, + ItemStack musket = EnchantmentHelper.enchantItem(random, new ItemStack(Items.blackpowder_musket), enchantmentLevel, false); int price = Math.min(randomPrice(random, 15, 25) + enchantmentLevel, 64); return offer(price, musket); diff --git a/src/main/java/zone/moddev/mc/steamadvantage/items/MusketItem.java b/src/main/java/zone/moddev/mc/steamadvantage/items/MusketItem.java index 69d44da..dd8bd11 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/items/MusketItem.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/items/MusketItem.java @@ -18,14 +18,14 @@ import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.attributes.Attributes; +import net.minecraft.entity.ai.attributes.Attribute; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.util.SoundEvents; import net.minecraft.inventory.EquipmentSlotType; import net.minecraft.item.UseAction; -import net.minecraft.item.IItemPropertyGetter; import net.minecraft.item.ItemStack; import net.minecraft.item.Item; import net.minecraft.particles.ParticleTypes; @@ -43,7 +43,7 @@ import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.EntityRayTraceResult; import net.minecraft.util.math.RayTraceContext; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; @@ -65,23 +65,7 @@ public class MusketItem extends net.minecraft.item.Item{ private static final ResourceLocation STEEL_INGOT_TAG = new ResourceLocation("forge", "ingots/steel"); public MusketItem(Item.Properties properties){ - super(properties.defaultMaxDamage(250)); - this.addPropertyOverride(new ResourceLocation("loaded"), new IItemPropertyGetter() - { - @OnlyIn(Dist.CLIENT) - public float call(ItemStack item, World w, LivingEntity e) - { - return isLoaded(item) ? 1.0F : 0.0F; - } - }); - this.addPropertyOverride(new ResourceLocation("loading"), new IItemPropertyGetter() - { - @OnlyIn(Dist.CLIENT) - public float call(ItemStack item, World w, LivingEntity e) - { - return e != null && e.isHandActive() && e.getActiveItemStack() == item ? 1.0F : 0.0F; - } - }); + super(properties.defaultDurability(250)); } @@ -96,12 +80,12 @@ public static float getMeleeDamage(){ } @Override - public int getItemEnchantability(){ + public int getEnchantmentValue(){ return 1; } @Override - public UseAction getUseAction(ItemStack stack){ + public UseAction getUseAnimation(ItemStack stack){ if(isLoaded(stack)){ return UseAction.BOW; } else { @@ -110,25 +94,25 @@ public UseAction getUseAction(ItemStack stack){ } @Override - public ActionResult onItemRightClick(World world, PlayerEntity playerEntity, Hand hand){ - ItemStack srcItemStack = playerEntity.getHeldItem(hand); - if(hand != Hand.MAIN_HAND) return ActionResult.resultPass(srcItemStack); - if(!hasAmmo(playerEntity, srcItemStack)) return ActionResult.resultFail(srcItemStack); - if(isNotLoaded(srcItemStack) && EnchantmentHelper.getEnchantmentLevel(Enchantments.rapid_reload, srcItemStack) > 0){ + public ActionResult use(World world, PlayerEntity playerEntity, Hand hand){ + ItemStack srcItemStack = playerEntity.getItemInHand(hand); + if(hand != Hand.MAIN_HAND) return ActionResult.pass(srcItemStack); + if(!hasAmmo(playerEntity, srcItemStack)) return ActionResult.fail(srcItemStack); + if(isNotLoaded(srcItemStack) && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.rapid_reload, srcItemStack) > 0){ // instant reload decrementAmmo(playerEntity,srcItemStack); startLoad(srcItemStack); - playSound(SoundEvents.BLOCK_LEVER_CLICK,world,playerEntity); + playSound(SoundEvents.LEVER_CLICK,world,playerEntity); finishLoad(srcItemStack); - return ActionResult.resultSuccess(srcItemStack); + return ActionResult.success(srcItemStack); } - playerEntity.setActiveHand(hand); - return ActionResult.resultSuccess(srcItemStack); + playerEntity.startUsingItem(hand); + return ActionResult.success(srcItemStack); } @Override public void onUsingTick(ItemStack stack, LivingEntity player, int count){ - if(player.world.isRemote && count % 7 == 3 && isNotLoaded(stack)){ + if(player.level.isClientSide && count % 7 == 3 && isNotLoaded(stack)){ // indicator to player that the gun is loading player.playSound(SoundType.STONE.getStepSound(), 0.5f, 1.0f); } @@ -138,18 +122,18 @@ public void onUsingTick(ItemStack stack, LivingEntity player, int count){ * provided to the PlayerEntity.setItemInUse(stack, duration). */ @Override - public ItemStack onItemUseFinish (ItemStack srcItemStack, World world, LivingEntity playerEntity) + public ItemStack finishUsingItem (ItemStack srcItemStack, World world, LivingEntity playerEntity) { // if(isNotLoaded(srcItemStack) && hasAmmo(playerEntity,srcItemStack)){ decrementAmmo(playerEntity,srcItemStack); startLoad(srcItemStack); - playSound(SoundEvents.BLOCK_LEVER_CLICK,world,playerEntity); + playSound(SoundEvents.LEVER_CLICK,world,playerEntity); } return srcItemStack; } @Override - public void onPlayerStoppedUsing(ItemStack stack, World worldIn, LivingEntity playerIn, int timeLeft) { + public void releaseUsing(ItemStack stack, World worldIn, LivingEntity playerIn, int timeLeft) { if(isAlmostLoaded(stack)){ finishLoad(stack); } else if(isLoaded(stack)){ @@ -162,19 +146,19 @@ protected void fire(ItemStack srcItemStack, LivingEntity playerEntity, final boolean isPlayer = playerEntity instanceof PlayerEntity; unload(srcItemStack); if(isPlayer && !((PlayerEntity)playerEntity).isCreative()){ - srcItemStack.damageItem(1, playerEntity, entity -> entity.sendBreakAnimation(EquipmentSlotType.MAINHAND)); + srcItemStack.hurtAndBreak(1, playerEntity, entity -> entity.broadcastBreakEvent(EquipmentSlotType.MAINHAND)); } - Vec3d lookVector = playerEntity.getLookVec(); + Vector3d lookVector = playerEntity.getLookAngle(); spawnParticle(ParticleTypes.EXPLOSION_EMITTER, world, - playerEntity.getPosX()+lookVector.x, playerEntity.getPosY()+playerEntity.getEyeHeight()+lookVector.y, playerEntity.getPosZ() + lookVector.z); - if(world.isRemote){ - playerEntity.rotationPitch -= 15; + playerEntity.getX()+lookVector.x, playerEntity.getY()+playerEntity.getEyeHeight()+lookVector.y, playerEntity.getZ() + lookVector.z); + if(world.isClientSide){ + playerEntity.xRot -= 15; return; } - playSound(SoundEvents.ITEM_FLINTANDSTEEL_USE,world,playerEntity); - playBigSoundAtPosition(playerEntity.getPosX(),playerEntity.getPosY(),playerEntity.getPosZ(), SoundEvents.ENTITY_FIREWORK_ROCKET_BLAST,SoundCategory.PLAYERS,2F,0.5F,world); + playSound(SoundEvents.FLINTANDSTEEL_USE,world,playerEntity); + playBigSoundAtPosition(playerEntity.getX(),playerEntity.getY(),playerEntity.getZ(), SoundEvents.FIREWORK_ROCKET_BLAST,SoundCategory.PLAYERS,2F,0.5F,world); - Vec3d start = new Vec3d(playerEntity.getPosX(), playerEntity.getPosY()+playerEntity.getEyeHeight(),playerEntity.getPosZ()); + Vector3d start = new Vector3d(playerEntity.getX(), playerEntity.getY()+playerEntity.getEyeHeight(),playerEntity.getZ()); start.add(MAX_RANGE * lookVector.x, MAX_RANGE * lookVector.y, MAX_RANGE * lookVector.z); RayTraceResult rayTrace = rayTraceBlocksAndEntities(world,MAX_RANGE,playerEntity); if(rayTrace == null){ @@ -184,71 +168,71 @@ protected void fire(ItemStack srcItemStack, LivingEntity playerEntity, final float explodeFactor = 0.75f; if(rayTrace instanceof EntityRayTraceResult){ Entity e = ((EntityRayTraceResult) rayTrace).getEntity(); - e.attackEntityFrom(Power.musket_damage, getShotDamage()); - if(EnchantmentHelper.getEnchantmentLevel(Enchantments.high_explosive, srcItemStack) > 0){ - int lvl = EnchantmentHelper.getEnchantmentLevel(Enchantments.high_explosive, srcItemStack); - world.createExplosion(playerEntity, e.getPosX(), e.getPosY()+0.5, e.getPosZ(), + e.hurt(Power.musket_damage, getShotDamage()); + if(EnchantmentHelper.getItemEnchantmentLevel(Enchantments.high_explosive, srcItemStack) > 0){ + int lvl = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.high_explosive, srcItemStack); + world.explode(playerEntity, e.getX(), e.getY()+0.5, e.getZ(), explodeFactor * lvl, Explosion.Mode.BREAK); - AxisAlignedBB fireArea = new AxisAlignedBB(e.getPosX()-lvl, e.getPosY()-lvl, e.getPosZ()-lvl, - e.getPosX()+lvl, e.getPosY()+lvl, e.getPosZ()+lvl); - List collateralDamage = world.getEntitiesWithinAABB(LivingEntity.class, fireArea); + AxisAlignedBB fireArea = new AxisAlignedBB(e.getX()-lvl, e.getY()-lvl, e.getZ()-lvl, + e.getX()+lvl, e.getY()+lvl, e.getZ()+lvl); + List collateralDamage = world.getEntitiesOfClass(LivingEntity.class, fireArea); for(LivingEntity victim : collateralDamage){ - victim.setFire(lvl); + victim.setSecondsOnFire(lvl); } } } else if(rayTrace.getType() == RayTraceResult.Type.BLOCK){ - playSoundAtPosition(rayTrace.getHitVec().x, rayTrace.getHitVec().y, rayTrace.getHitVec().z, - SoundEvents.BLOCK_GRAVEL_HIT, SoundCategory.BLOCKS, 1f, 1f, world); - BlockPos coord = ((BlockRayTraceResult) rayTrace).getPos(); - if(coord.getY()>= 0 && coord.getY() <= 255 && !world.isAirBlock(coord)){ + playSoundAtPosition(rayTrace.getLocation().x, rayTrace.getLocation().y, rayTrace.getLocation().z, + SoundEvents.GRAVEL_HIT, SoundCategory.BLOCKS, 1f, 1f, world); + BlockPos coord = ((BlockRayTraceResult) rayTrace).getBlockPos(); + if(coord.getY()>= 0 && coord.getY() <= 255 && !world.isEmptyBlock(coord)){ BlockState bs = world.getBlockState(coord); - Material blockMat = bs.getBlock().getMaterial(bs); + Material blockMat = bs.getMaterial(); if(blockMat == net.minecraft.block.material.Material.GLASS || blockMat == net.minecraft.block.material.Material.LEAVES - || blockMat == net.minecraft.block.material.Material.MISCELLANEOUS - || blockMat == net.minecraft.block.material.Material.PLANTS - || blockMat == net.minecraft.block.material.Material.TALL_PLANTS + || blockMat == net.minecraft.block.material.Material.DECORATION + || blockMat == net.minecraft.block.material.Material.PLANT + || blockMat == net.minecraft.block.material.Material.REPLACEABLE_PLANT || blockMat == net.minecraft.block.material.Material.WEB){ world.destroyBlock(coord, true); - } else if (blockMat == net.minecraft.block.material.Material.TNT){ + } else if (blockMat == net.minecraft.block.material.Material.EXPLOSIVE){ if(world.getBlockState(coord).getBlock() instanceof TNTBlock){ TNTBlock.explode(world, coord); world.removeBlock(coord, false); } } } - if(EnchantmentHelper.getEnchantmentLevel(Enchantments.high_explosive, srcItemStack) > 0){ - int lvl = EnchantmentHelper.getEnchantmentLevel(Enchantments.high_explosive, srcItemStack); - world.createExplosion(playerEntity, rayTrace.getHitVec().x, rayTrace.getHitVec().y, rayTrace.getHitVec().z, + if(EnchantmentHelper.getItemEnchantmentLevel(Enchantments.high_explosive, srcItemStack) > 0){ + int lvl = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.high_explosive, srcItemStack); + world.explode(playerEntity, rayTrace.getLocation().x, rayTrace.getLocation().y, rayTrace.getLocation().z, explodeFactor * lvl, Explosion.Mode.BREAK); - AxisAlignedBB fireArea = new AxisAlignedBB(rayTrace.getHitVec().x-lvl, rayTrace.getHitVec().y-lvl, rayTrace.getHitVec().z-lvl, - rayTrace.getHitVec().x+lvl, rayTrace.getHitVec().y+lvl, rayTrace.getHitVec().z+lvl); - List collateralDamage = world.getEntitiesWithinAABB(LivingEntity.class, fireArea); + AxisAlignedBB fireArea = new AxisAlignedBB(rayTrace.getLocation().x-lvl, rayTrace.getLocation().y-lvl, rayTrace.getLocation().z-lvl, + rayTrace.getLocation().x+lvl, rayTrace.getLocation().y+lvl, rayTrace.getLocation().z+lvl); + List collateralDamage = world.getEntitiesOfClass(LivingEntity.class, fireArea); for(LivingEntity victim : collateralDamage){ - victim.setFire(lvl); + victim.setSecondsOnFire(lvl); } } } if(rayTrace.getType() != RayTraceResult.Type.MISS){ spawnParticle(ParticleTypes.LARGE_SMOKE, world, - rayTrace.getHitVec().x, rayTrace.getHitVec().y, rayTrace.getHitVec().z); + rayTrace.getLocation().x, rayTrace.getLocation().y, rayTrace.getLocation().z); spawnParticle(ParticleTypes.EXPLOSION, world, - rayTrace.getHitVec().x, rayTrace.getHitVec().y, rayTrace.getHitVec().z); + rayTrace.getLocation().x, rayTrace.getLocation().y, rayTrace.getLocation().z); } // recoil enchantment kicks you back - int recoil = EnchantmentHelper.getEnchantmentLevel(Enchantments.recoil, srcItemStack); + int recoil = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.recoil, srcItemStack); if(recoil > 0){ double c = -0.3; double lateral = 2.0; - playerEntity.addVelocity(c * recoil * lookVector.x * lateral, + playerEntity.push(c * recoil * lookVector.x * lateral, c * recoil * lookVector.y, c * recoil * lookVector.z * lateral); if(playerEntity instanceof ServerPlayerEntity){ // send update packet from server - ((ServerPlayerEntity) playerEntity).connection.sendPacket(new SEntityVelocityPacket(playerEntity)); + ((ServerPlayerEntity) playerEntity).connection.send(new SEntityVelocityPacket(playerEntity)); } } } @@ -256,24 +240,24 @@ protected void fire(ItemStack srcItemStack, LivingEntity playerEntity, private void spawnParticle(IParticleData p, World w, double x, double y, double z) { if(w instanceof ServerWorld) { - ((ServerWorld) w).spawnParticle(p, x, y, z, 1, 0, 0, 0, 0); + ((ServerWorld) w).sendParticles(p, x, y, z, 1, 0, 0, 0, 0); } else { w.addParticle(p, x, y, z, 0, 0, 0); } } @Override - public boolean hitEntity(ItemStack stack, LivingEntity target, LivingEntity attacker) + public boolean hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) { - stack.damageItem(1, attacker, entity -> entity.sendBreakAnimation(EquipmentSlotType.MAINHAND)); + stack.hurtAndBreak(1, attacker, entity -> entity.broadcastBreakEvent(EquipmentSlotType.MAINHAND)); return true; } /** plays a sound at the player location */ protected void playSound(SoundEvent sound, World world, Entity e){ - if (!world.isRemote) + if (!world.isClientSide) { - playSoundAtPosition(e.getPosX(), e.getPosY(), e.getPosZ(), sound,SoundCategory.PLAYERS,1F,1F,world); + playSoundAtPosition(e.getX(), e.getY(), e.getZ(), sound,SoundCategory.PLAYERS,1F,1F,world); } } @@ -334,12 +318,12 @@ public static boolean hasAmmo(LivingEntity e, ItemStack musket) { if(e instanceof PlayerEntity) { PlayerEntity playerEntity = (PlayerEntity) e; if (playerEntity.isCreative() - || EnchantmentHelper.getEnchantmentLevel(net.minecraft.enchantment.Enchantments.INFINITY, musket) > 0 - || EnchantmentHelper.getEnchantmentLevel(Enchantments.powderless, musket) > 0) return true; - for (int i = 0; i < playerEntity.inventory.mainInventory.size(); i++) { - ItemStack inventoryStack = playerEntity.inventory.mainInventory.get(i); + || EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.enchantment.Enchantments.INFINITY_ARROWS, musket) > 0 + || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.powderless, musket) > 0) return true; + for (int i = 0; i < playerEntity.inventory.items.size(); i++) { + ItemStack inventoryStack = playerEntity.inventory.items.get(i); if (inventoryStack.isEmpty()) continue; - if (ItemTags.getCollection().getOrCreate(BLACKPOWDER_AMMO_TAG).contains(inventoryStack.getItem())) return true; + if (ItemTags.getAllTags().getTagOrEmpty(BLACKPOWDER_AMMO_TAG).contains(inventoryStack.getItem())) return true; } } return false; @@ -350,14 +334,14 @@ public static void decrementAmmo(LivingEntity e, ItemStack musket) { if(e instanceof PlayerEntity) { PlayerEntity playerEntity = (PlayerEntity) e; if (playerEntity.isCreative() - || EnchantmentHelper.getEnchantmentLevel(net.minecraft.enchantment.Enchantments.INFINITY, musket) > 0 - || EnchantmentHelper.getEnchantmentLevel(Enchantments.powderless, musket) > 0) return; - for (int i = 0; i < playerEntity.inventory.mainInventory.size(); i++) { - ItemStack inventoryStack = playerEntity.inventory.mainInventory.get(i); + || EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.enchantment.Enchantments.INFINITY_ARROWS, musket) > 0 + || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.powderless, musket) > 0) return; + for (int i = 0; i < playerEntity.inventory.items.size(); i++) { + ItemStack inventoryStack = playerEntity.inventory.items.get(i); if (inventoryStack.isEmpty()) continue; - if (ItemTags.getCollection().getOrCreate(BLACKPOWDER_AMMO_TAG).contains(inventoryStack.getItem())) { + if (ItemTags.getAllTags().getTagOrEmpty(BLACKPOWDER_AMMO_TAG).contains(inventoryStack.getItem())) { inventoryStack.shrink(1); - if (inventoryStack.isEmpty()) playerEntity.inventory.mainInventory.set(i, ItemStack.EMPTY); + if (inventoryStack.isEmpty()) playerEntity.inventory.items.set(i, ItemStack.EMPTY); return; } } @@ -367,16 +351,16 @@ public static void decrementAmmo(LivingEntity e, ItemStack musket) { public static RayTraceResult rayTraceBlocksAndEntities(World w, double maxRange, LivingEntity source){ double rangeSqr = maxRange * maxRange; - Vec3d rayOrigin = new Vec3d(source.getPosX(), source.getPosY() + source.getEyeHeight(), source.getPosZ()); - Vec3d rayDirection = source.getLookVec(); - BlockPos srcPos = source.getPosition(); + Vector3d rayOrigin = new Vector3d(source.getX(), source.getY() + source.getEyeHeight(), source.getZ()); + Vector3d rayDirection = source.getLookAngle(); + BlockPos srcPos = source.blockPosition(); AxisAlignedBB aoi = new AxisAlignedBB(srcPos.getX() - maxRange, srcPos.getY() - maxRange, srcPos.getZ() - maxRange, srcPos.getX() + maxRange, srcPos.getY() + maxRange, srcPos.getZ() + maxRange); - List entities = w.getEntitiesWithinAABBExcludingEntity(source, aoi); + List entities = w.getEntities(source, aoi); double closestDistSqr = Double.MAX_VALUE; Entity closestEntity = null; for(Entity e : entities){ - double distSqr = e.getDistanceSq(source.getPosX(), source.getPosY(), source.getPosZ()); + double distSqr = e.distanceToSqr(source.getX(), source.getY(), source.getZ()); if(distSqr < rangeSqr){ // e is within range AxisAlignedBB box = e.getBoundingBox(); @@ -391,19 +375,19 @@ public static RayTraceResult rayTraceBlocksAndEntities(World w, double maxRange, } } if(closestEntity == null) { - return w.rayTraceBlocks(new RayTraceContext(rayOrigin, rayOrigin.add(mul(rayDirection, maxRange)), + return w.clip(new RayTraceContext(rayOrigin, rayOrigin.add(mul(rayDirection, maxRange)), RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.SOURCE_ONLY, source)); } else { - Vec3d pos = new Vec3d(closestEntity.getPosX(), closestEntity.getPosY()+closestEntity.getEyeHeight(), closestEntity.getPosZ()); + Vector3d pos = new Vector3d(closestEntity.getX(), closestEntity.getY()+closestEntity.getEyeHeight(), closestEntity.getZ()); RayTraceResult entityCollision = new EntityRayTraceResult(closestEntity, pos); return entityCollision; } } - 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; @@ -430,8 +414,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); @@ -443,15 +427,15 @@ private static double min(double a, double b){ /** * Return whether this item is repairable in an anvil. */ - @Override public boolean getIsRepairable(ItemStack srcItemStack, ItemStack rawMaterial) + @Override public boolean isValidRepairItem(ItemStack srcItemStack, ItemStack rawMaterial) { // repair with steel ingots - return ItemTags.getCollection().getOrCreate(STEEL_INGOT_TAG).contains(rawMaterial.getItem()); + return ItemTags.getAllTags().getTagOrEmpty(STEEL_INGOT_TAG).contains(rawMaterial.getItem()); } @Override - public void addInformation(ItemStack stack, World world, List list, net.minecraft.client.util.ITooltipFlag flag){ - super.addInformation(stack,world,list,flag); + public void appendHoverText(ItemStack stack, World world, List list, net.minecraft.client.util.ITooltipFlag flag){ + super.appendHoverText(stack,world,list,flag); list.add(new TranslationTextComponent("tooltip.musket.damage", (int)MusketItem.getShotDamage())); if(isLoaded(stack)){ list.add(new TranslationTextComponent("tooltip.musket.loaded")); @@ -463,11 +447,11 @@ public void addInformation(ItemStack stack, World world, List li /** Sets melee attack damage */ @Override - public Multimap getAttributeModifiers(EquipmentSlotType slot, ItemStack stack) + public Multimap getAttributeModifiers(EquipmentSlotType slot, ItemStack stack) { - Multimap multimap = HashMultimap.create(); + Multimap multimap = HashMultimap.create(); if(slot != EquipmentSlotType.MAINHAND) return multimap; - multimap.put(SharedMonsterAttributes.ATTACK_DAMAGE.getName(), new AttributeModifier(ATTACK_DAMAGE_MODIFIER, "Weapon modifier", (double)getMeleeDamage(), AttributeModifier.Operation.ADDITION)); + multimap.put(Attributes.ATTACK_DAMAGE, new AttributeModifier(BASE_ATTACK_DAMAGE_UUID, "Weapon modifier", (double)getMeleeDamage(), AttributeModifier.Operation.ADDITION)); return multimap; } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/BlastFurnaceBlock.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/BlastFurnaceBlock.java index a25374d..b720793 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/BlastFurnaceBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/BlastFurnaceBlock.java @@ -21,19 +21,19 @@ public BlastFurnaceBlock() { } @Override - public PoweredEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public PoweredEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new BlastFurnaceTileEntity(); } @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 BlastFurnaceTileEntity){ - return ((BlastFurnaceTileEntity)world.getTileEntity(coord)).getComparatorOutput(); + public int getAnalogOutputSignal(BlockState bs, World world, BlockPos coord) { + if(world.getBlockEntity(coord) instanceof BlastFurnaceTileEntity){ + return ((BlastFurnaceTileEntity)world.getBlockEntity(coord)).getComparatorOutput(); } return 0; } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/BlastFurnaceTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/BlastFurnaceTileEntity.java index 2ab9d80..47f1c61 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/BlastFurnaceTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/BlastFurnaceTileEntity.java @@ -77,7 +77,7 @@ public void tickUpdate(boolean isServerWorld) { burnTime = fuel; totalBurnTime = fuel; decrementFuel(); - playSoundAtTileEntity( SoundEvents.BLOCK_FURNACE_FIRE_CRACKLE, SoundCategory.AMBIENT, 0.5f, 1f, this); + playSoundAtTileEntity( SoundEvents.FURNACE_FIRE_CRACKLE, SoundCategory.AMBIENT, 0.5f, 1f, this); } energyDecay(); } @@ -103,7 +103,7 @@ public void tickUpdate(boolean isServerWorld) { inventory[slot].shrink(1); if(inventory[slot].isEmpty()){inventory[slot] = null;} // decrement the input slot if(!smeltSuccess){ - playSoundAtTileEntity(SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); + playSoundAtTileEntity(SoundEvents.FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); } smeltSuccess = true; } @@ -126,8 +126,8 @@ private boolean canSmelt(int slot) { if(output.isEmpty()) return false; ItemStack outputSlot = inventory[slot+3]; if(outputSlot == null) return true; - return (ItemStack.areItemsEqual(output, outputSlot) - && ItemStack.areItemStackTagsEqual(output, outputSlot) + return (ItemStack.isSame(output, outputSlot) + && ItemStack.tagMatches(output, outputSlot) && (output.getCount() + outputSlot.getCount()) <= outputSlot.getMaxStackSize()); } @@ -175,7 +175,7 @@ public void powerUpdate(){ } private boolean hasRedstoneSignal() { - return getWorld().isBlockPowered(getPos()); + return getLevel().hasNeighborSignal(getBlockPos()); } @@ -194,7 +194,7 @@ private void decrementFuel() { if(inventory[0].getCount() == 1 && inventory[0].getItem().getContainerItem(inventory[0]) != null){ inventory[0] = inventory[0].getItem().getContainerItem(inventory[0]); } else { - this.decrStackSize(0, 1); + this.removeItem(0, 1); } } @@ -252,16 +252,16 @@ public void onDataFieldUpdate() { @Override - public CompoundNBT write(CompoundNBT tagRoot){ - super.write(tagRoot); + public CompoundNBT save(CompoundNBT tagRoot){ + super.save(tagRoot); prepareDataFieldsForSync(); tagRoot.putIntArray("Data", getDataFieldArray()); return tagRoot; } @Override - public void read(CompoundNBT tagRoot){ - super.read(tagRoot); + public void load(net.minecraft.block.BlockState state, CompoundNBT tagRoot){ + super.load(state, tagRoot); if(tagRoot.contains("Data")){ int[] data = tagRoot.getIntArray("Data"); System.arraycopy(data, 0, this.getDataFieldArray(), 0, Math.min(data.length,this.getDataFieldArray().length)); @@ -289,17 +289,17 @@ 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 slot >= 4 && slot < this.getInventory().length; } @Override - public boolean canInsertItem(final int slot, final ItemStack srcItem, final Direction side) { - return this.isItemValidForSlot(slot, srcItem) && slot <= 3; + public boolean canPlaceItemThroughFace(final int slot, final ItemStack srcItem, final Direction side) { + return this.canPlaceItem(slot, srcItem) && slot <= 3; } @Override - public boolean isItemValidForSlot(final int slot, final ItemStack item) { + public boolean canPlaceItem(final int slot, final ItemStack item) { switch(slot){ case 0: return this.getFuelBurnTime(item) > 0; @@ -317,11 +317,11 @@ public boolean isItemValidForSlot(final int slot, final ItemStack item) { } private ItemStack getSmeltingResult(ItemStack input) { - if (input == null || input.isEmpty() || getWorld() == null) return ItemStack.EMPTY; + if (input == null || input.isEmpty() || 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); } @@ -336,7 +336,7 @@ public boolean isPowerSource(ConduitType powerType) { } @Override - public boolean isUsableByPlayer(PlayerEntity player) { + public boolean stillValid(PlayerEntity player) { return true; } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerBlock.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerBlock.java index 3369b94..769986c 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerBlock.java @@ -26,19 +26,19 @@ public CoalBoilerBlock() { } @Override - public PoweredEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public PoweredEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new CoalBoilerTileEntity(); } @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 CoalBoilerTileEntity){ - return ((CoalBoilerTileEntity)world.getTileEntity(coord)).getComparatorOutput(); + public int getAnalogOutputSignal(BlockState bs, World world, BlockPos coord) { + if(world.getBlockEntity(coord) instanceof CoalBoilerTileEntity){ + return ((CoalBoilerTileEntity)world.getBlockEntity(coord)).getComparatorOutput(); } return 0; } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerTileEntity.java index 04d835a..6de623e 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerTileEntity.java @@ -55,12 +55,12 @@ public void tickUpdate(boolean isServerWorld) { burnTime--; boilWater(); // play steam sounds occasionally - if(getWorld().rand.nextInt(100) == 0){ - playSoundAtTileEntity(SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); + if(getLevel().random.nextInt(100) == 0){ + playSoundAtTileEntity(SoundEvents.FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); } if(timeSinceSound > 200){ if(getTank().getFluidAmount() > 0){ - playSoundAtTileEntity( SoundEvents.BLOCK_LAVA_AMBIENT, SoundCategory.AMBIENT, 0.3f, 1f, this); + playSoundAtTileEntity( SoundEvents.LAVA_AMBIENT, SoundCategory.AMBIENT, 0.3f, 1f, this); } timeSinceSound = 0; } @@ -84,7 +84,7 @@ public void tickUpdate(boolean isServerWorld) { private boolean hasRedstoneSignal() { - return getWorld().isBlockPowered(getPos()); + return getLevel().hasNeighborSignal(getBlockPos()); } @@ -105,7 +105,7 @@ private void decrementFuel() { if(inventory[0].getCount() == 1 && inventory[0].getItem().getContainerItem(inventory[0]) != null){ inventory[0] = inventory[0].getItem().getContainerItem(inventory[0]); } else { - this.decrStackSize(0, 1); + this.removeItem(0, 1); } } @@ -201,8 +201,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); @@ -215,8 +215,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(net.minecraft.block.BlockState state, final CompoundNBT tagRoot) { + super.load(state, tagRoot); if (tagRoot.contains("Tank")) { CompoundNBT tankTag = tagRoot.getCompound("Tank"); getTank().readFromNBT(tankTag); @@ -420,12 +420,12 @@ public FluidTankInfo[] getTankInfo(Direction face) { ///// end of IFluidHandler methods ///// @Override - public boolean isItemValidForSlot(final int slot, final ItemStack item) { - return super.isItemValidForSlot(slot, item) && zone.moddev.mc.steamadvantage.util.FurnaceFuelHelper.getBurnTime(item) > 0; + public boolean canPlaceItem(final int slot, final ItemStack item) { + return super.canPlaceItem(slot, item) && zone.moddev.mc.steamadvantage.util.FurnaceFuelHelper.getBurnTime(item) > 0; } @Override - public boolean isUsableByPlayer(PlayerEntity player) { + public boolean stillValid(PlayerEntity player) { return true; } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/ElectricBoilerBlock.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/ElectricBoilerBlock.java index a892f61..ab595f8 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/ElectricBoilerBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/ElectricBoilerBlock.java @@ -21,19 +21,19 @@ public ElectricBoilerBlock() { } @Override - public PoweredEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public PoweredEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new ElectricBoilerTileEntity(); } @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 ElectricBoilerTileEntity){ - return ((ElectricBoilerTileEntity)world.getTileEntity(coord)).getComparatorOutput(); + public int getAnalogOutputSignal(BlockState bs, World world, BlockPos coord) { + if(world.getBlockEntity(coord) instanceof ElectricBoilerTileEntity){ + return ((ElectricBoilerTileEntity)world.getBlockEntity(coord)).getComparatorOutput(); } return 0; } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/ElectricBoilerTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/ElectricBoilerTileEntity.java index a40d441..5aaa51c 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/ElectricBoilerTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/ElectricBoilerTileEntity.java @@ -55,12 +55,12 @@ public void tickUpdate(boolean isServerWorld) { if(!redstone && getEnergy(ELECTRIC_POWER) >= ELECTRICITY_PER_TICK){ boilWater(); // play steam sounds occasionally - if(getWorld().rand.nextInt(100) == 0){ - playSoundAtTileEntity( SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); + if(getLevel().random.nextInt(100) == 0){ + playSoundAtTileEntity( SoundEvents.FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); } if(timeSinceSound > 200){ if(getTank().getFluidAmount() > 0){ - playSoundAtTileEntity( SoundEvents.BLOCK_LAVA_AMBIENT, SoundCategory.AMBIENT, 0.3f, 1f, this); + playSoundAtTileEntity( SoundEvents.LAVA_AMBIENT, SoundCategory.AMBIENT, 0.3f, 1f, this); } timeSinceSound = 0; } @@ -73,7 +73,7 @@ public void tickUpdate(boolean isServerWorld) { private boolean hasRedstoneSignal() { - return getWorld().isBlockPowered(getPos()); + return getLevel().hasNeighborSignal(getBlockPos()); } @@ -84,7 +84,7 @@ private void energyDecay() { } @Override - public boolean isUsableByPlayer(PlayerEntity player) { + public boolean stillValid(PlayerEntity player) { return true; } @@ -174,8 +174,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); @@ -187,8 +187,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(net.minecraft.block.BlockState state, final CompoundNBT tagRoot) { + super.load(state, tagRoot); if (tagRoot.contains("Tank")) { CompoundNBT tankTag = tagRoot.getCompound("Tank"); getTank().readFromNBT(tankTag); @@ -372,7 +372,7 @@ public FluidTankInfo[] getTankInfo(Direction face) { ///// end of IFluidHandler methods ///// @Override - public boolean isItemValidForSlot(final int slot, final ItemStack item) { + public boolean canPlaceItem(final int slot, final ItemStack item) { return false; } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/GeothermalBoilerBlock.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/GeothermalBoilerBlock.java index 488ae45..4008652 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/GeothermalBoilerBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/GeothermalBoilerBlock.java @@ -18,19 +18,19 @@ public GeothermalBoilerBlock() { } @Override - public PoweredEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public PoweredEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new GeothermalBoilerTileEntity(); } @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 GeothermalBoilerTileEntity){ - return ((GeothermalBoilerTileEntity)world.getTileEntity(coord)).getComparatorOutput(); + public int getAnalogOutputSignal(BlockState bs, World world, BlockPos coord) { + if(world.getBlockEntity(coord) instanceof GeothermalBoilerTileEntity){ + return ((GeothermalBoilerTileEntity)world.getBlockEntity(coord)).getComparatorOutput(); } return 0; } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/GeothermalBoilerTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/GeothermalBoilerTileEntity.java index 0f921f6..8484e3f 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/GeothermalBoilerTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/GeothermalBoilerTileEntity.java @@ -48,7 +48,7 @@ public GeothermalBoilerTileEntity() { } @Override - public boolean isUsableByPlayer(PlayerEntity player) { + public boolean stillValid(PlayerEntity player) { return true; } @@ -63,12 +63,12 @@ public void tickUpdate(boolean isServerWorld) { if(!redstone && tank.getFluidAmount() > 0 && temperature >= ACTIVATION_TEMPERATURE){ boilWater(); // play steam sounds occasionally - if(getWorld().rand.nextInt(100) == 0){ - playSoundAtTileEntity( SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); + if(getLevel().random.nextInt(100) == 0){ + playSoundAtTileEntity( SoundEvents.FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); } if(timeSinceSound > 200){ if(getTank().getFluidAmount() > 0){ - playSoundAtTileEntity( SoundEvents.BLOCK_LAVA_AMBIENT, SoundCategory.AMBIENT, 0.3f, 1f, this); + playSoundAtTileEntity( SoundEvents.LAVA_AMBIENT, SoundCategory.AMBIENT, 0.3f, 1f, this); } timeSinceSound = 0; } @@ -82,7 +82,7 @@ public void tickUpdate(boolean isServerWorld) { private boolean hasRedstoneSignal() { - return getWorld().isBlockPowered(getPos()); + return getLevel().hasNeighborSignal(getBlockPos()); } @@ -95,9 +95,9 @@ private void energyDecay() { private void updateTemperature(){ float themalInput = 0; for(Direction f : Direction.values()){ - BlockPos p = getPos().offset(f); + BlockPos p = getBlockPos().relative(f); if(p.getY() >= 0 && p.getY() < 256){ - themalInput += thermalEnergy(getWorld().getBlockState(p)); + themalInput += thermalEnergy(getLevel().getBlockState(p)); } } float tSqr = temperature * temperature; @@ -109,7 +109,7 @@ private static float thermalEnergy(BlockState bs){ Block b = bs.getBlock(); if(b == net.minecraft.block.Blocks.FIRE){ return 200; - } else if(bs.getFluidState().getFluid().isEquivalentTo(net.minecraft.fluid.Fluids.LAVA)) { + } else if(bs.getFluidState().getType().isSame(net.minecraft.fluid.Fluids.LAVA)) { // Forge 1.13 native fluids no longer expose the old temperature property. return (1300 - 372) * 0.5f; } else { @@ -208,8 +208,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); @@ -221,8 +221,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(net.minecraft.block.BlockState state, final CompoundNBT tagRoot) { + super.load(state, tagRoot); if (tagRoot.contains("Tank")) { CompoundNBT tankTag = tagRoot.getCompound("Tank"); getTank().readFromNBT(tankTag); @@ -408,7 +408,7 @@ public FluidTankInfo[] getTankInfo(Direction face) { ///// end of IFluidHandler methods ///// @Override - public boolean isItemValidForSlot(final int slot, final ItemStack item) { + public boolean canPlaceItem(final int slot, final ItemStack item) { return false; } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/OilBoilerBlock.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/OilBoilerBlock.java index 4d5de8f..63d82df 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/OilBoilerBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/OilBoilerBlock.java @@ -26,19 +26,19 @@ public OilBoilerBlock() { } @Override - public PoweredEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public PoweredEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new OilBoilerTileEntity(); } @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 OilBoilerTileEntity){ - return ((OilBoilerTileEntity)world.getTileEntity(coord)).getComparatorOutput(); + public int getAnalogOutputSignal(BlockState bs, World world, BlockPos coord) { + if(world.getBlockEntity(coord) instanceof OilBoilerTileEntity){ + return ((OilBoilerTileEntity)world.getBlockEntity(coord)).getComparatorOutput(); } return 0; } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/OilBoilerTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/OilBoilerTileEntity.java index 3905166..0a63f2a 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/OilBoilerTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/OilBoilerTileEntity.java @@ -62,12 +62,12 @@ public void tickUpdate(boolean isServerWorld) { burnTime--; boilWater(); // play steam sounds occasionally - if(getWorld().rand.nextInt(100) == 0){ - playSoundAtTileEntity( SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); + if(getLevel().random.nextInt(100) == 0){ + playSoundAtTileEntity( SoundEvents.FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); } if(timeSinceSound > 200){ if(getWaterTank().getFluidAmount() > 0){ - playSoundAtTileEntity( SoundEvents.BLOCK_LAVA_AMBIENT, SoundCategory.AMBIENT, 0.3f, 1f, this); + playSoundAtTileEntity( SoundEvents.LAVA_AMBIENT, SoundCategory.AMBIENT, 0.3f, 1f, this); } timeSinceSound = 0; } @@ -88,12 +88,12 @@ public void tickUpdate(boolean isServerWorld) { } @Override - public boolean isUsableByPlayer(PlayerEntity player) { + public boolean stillValid(PlayerEntity player) { return true; } private boolean hasRedstoneSignal() { - return getWorld().isBlockPowered(getPos()); + return getLevel().hasNeighborSignal(getBlockPos()); } @@ -121,8 +121,8 @@ private static Float getBurnTimePerBucketFor(Fluid fluid){ } // second, check universal bucket fuel registry int vol = FluidTank.BUCKET_VOLUME; - ItemStack bucket = fluid.getFilledBucket() == net.minecraft.item.Items.AIR - ? ItemStack.EMPTY : new ItemStack(fluid.getFilledBucket()); + ItemStack bucket = fluid.getBucket() == net.minecraft.item.Items.AIR + ? ItemStack.EMPTY : new ItemStack(fluid.getBucket()); if(bucket.isEmpty()){ flammibilityCache.put(fluid,0f); return 0f; @@ -259,8 +259,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.getWaterTank().writeToNBT(tankTag); tagRoot.put("WaterTank", tankTag); @@ -276,8 +276,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(net.minecraft.block.BlockState state, final CompoundNBT tagRoot) { + super.load(state, tagRoot); if (tagRoot.contains("WaterTank")) { CompoundNBT tankTag = tagRoot.getCompound("WaterTank"); getWaterTank().readFromNBT(tankTag); @@ -505,7 +505,7 @@ public FluidTankInfo[] getTankInfo(Direction face) { ///// end of IFluidHandler methods ///// @Override - public boolean isItemValidForSlot(final int slot, final ItemStack item) { + public boolean canPlaceItem(final int slot, final ItemStack item) { return false; // no inventory } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/RockCrusherBlock.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/RockCrusherBlock.java index cf87c1a..378fbbe 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/RockCrusherBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/RockCrusherBlock.java @@ -21,19 +21,19 @@ public RockCrusherBlock() { } @Override - public PoweredEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public PoweredEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new RockCrusherTileEntity(); } @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 RockCrusherTileEntity){ - return ((RockCrusherTileEntity)world.getTileEntity(coord)).getComparatorOutput(); + public int getAnalogOutputSignal(BlockState bs, World world, BlockPos coord) { + if(world.getBlockEntity(coord) instanceof RockCrusherTileEntity){ + return ((RockCrusherTileEntity)world.getBlockEntity(coord)).getComparatorOutput(); } return 0; } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/RockCrusherTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/RockCrusherTileEntity.java index daa0356..fb9e7a8 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/RockCrusherTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/RockCrusherTileEntity.java @@ -43,7 +43,7 @@ public void tickUpdate(boolean isServerWorld) { if(isServerWorld){ // reset progress when item in slot changes ItemStack input = inventory[0]; - if(itemCheck != null && (input == null || input.isEmpty() || ItemStack.areItemsEqual(itemCheck, input) == false)){ + if(itemCheck != null && (input == null || input.isEmpty() || ItemStack.isSame(itemCheck, input) == false)){ progress = 0; } itemCheck = (input == null || input.isEmpty()) ? null : input.copy(); @@ -71,7 +71,7 @@ public void tickUpdate(boolean isServerWorld) { // play steam sounds occasionally timeSinceLastSteamBurst++; if(timeSinceLastSteamBurst > 50){ - playSoundAtTileEntity( SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); + playSoundAtTileEntity( SoundEvents.FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); timeSinceLastSteamBurst = 0; } } else if (progress > 0){ @@ -88,7 +88,7 @@ public void tickUpdate(boolean isServerWorld) { inventory[0].shrink(1); if(inventory[0].isEmpty()){inventory[0] = null;} // decrement the input slot progress = 0; - playSoundAtTileEntity( SoundEvents.BLOCK_GRAVEL_BREAK, SoundCategory.AMBIENT, 0.5f, 0.2f, this); + playSoundAtTileEntity( SoundEvents.GRAVEL_BREAK, SoundCategory.AMBIENT, 0.5f, 0.2f, this); } } else if (progress > 0){ // cannot crush, undo progress @@ -101,7 +101,7 @@ public void tickUpdate(boolean isServerWorld) { } @Override - public boolean isUsableByPlayer(PlayerEntity player) { + public boolean stillValid(PlayerEntity player) { return true; } @@ -131,11 +131,11 @@ private void energyDecay() { private ItemStack getCrusherRecipeOutput(ItemStack item) { if(item == null) return null; - return BaseMetalsCompat.getCrusherRecipeOutput(getWorld(), item); + return BaseMetalsCompat.getCrusherRecipeOutput(getLevel(), item); } private boolean hasRedstoneSignal() { - return getWorld().isBlockPowered(getPos()); + return getLevel().hasNeighborSignal(getBlockPos()); } public float getProgressLevel(){ @@ -173,7 +173,7 @@ public void onDataFieldUpdate() { private int canAddToOutputInventory(ItemStack output) { for(int i = 1; i < inventory.length; i++){ if(inventory[i] == null) {return i;} - if(ItemStack.areItemsEqual(output, inventory[i]) && ItemStack.areItemStackTagsEqual(output, inventory[i]) + if(ItemStack.isSame(output, inventory[i]) && ItemStack.tagMatches(output, inventory[i]) && (inventory[i].getCount() + output.getCount()) <= inventory[i].getMaxStackSize()){ return i; } @@ -182,15 +182,15 @@ private int canAddToOutputInventory(ItemStack output) { } @Override - public CompoundNBT write(CompoundNBT tagRoot){ - super.write(tagRoot); + public CompoundNBT save(CompoundNBT tagRoot){ + super.save(tagRoot); tagRoot.putShort("progress",(short)progress); return tagRoot; } @Override - public void read(CompoundNBT tagRoot){ - super.read(tagRoot); + public void load(net.minecraft.block.BlockState state, CompoundNBT tagRoot){ + super.load(state, tagRoot); if(tagRoot.contains("progress")){ progress = tagRoot.getShort("progress"); } @@ -211,20 +211,20 @@ 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 slot > 0 && slot < this.getInventory().length; } @Override - public boolean canInsertItem(final int slot, final ItemStack srcItem, final Direction side) { - return this.isItemValidForSlot(slot, srcItem) && slot <= 0; + public boolean canPlaceItemThroughFace(final int slot, final ItemStack srcItem, final Direction side) { + return this.canPlaceItem(slot, srcItem) && slot <= 0; } @Override - public boolean isItemValidForSlot(final int slot, final ItemStack item) { + public boolean canPlaceItem(final int slot, final ItemStack item) { switch(slot){ case 0: - return BaseMetalsCompat.hasCrusherRecipe(getWorld(), item); + return BaseMetalsCompat.hasCrusherRecipe(getLevel(), item); case 1: case 2: case 3: diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamDrillBlock.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamDrillBlock.java index f481e46..0a9fa2b 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamDrillBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamDrillBlock.java @@ -33,47 +33,47 @@ public class SteamDrillBlock extends GUIBlock implements ITypedConduit { public SteamDrillBlock(){ super(Material.PISTON, 0.75f); - this.setDefaultState(getStateContainer().getBaseState().with(FACING, Direction.DOWN)); + this.registerDefaultState(getStateDefinition().any().setValue(FACING, Direction.DOWN)); } /** * Override of default block behavior */ @Override - public void onBlockAdded(final BlockState state, final World world, final BlockPos coord, final BlockState oldState, final boolean moving) { - super.onBlockAdded(state, world, coord, oldState, moving); - ConduitRegistry.getInstance().conduitBlockPlacedEvent(world, world.dimension.getType().getId(), coord, Power.steam_power); + public void onPlace(final BlockState state, final World world, final BlockPos coord, final BlockState oldState, final boolean moving) { + super.onPlace(state, world, coord, oldState, moving); + ConduitRegistry.getInstance().conduitBlockPlacedEvent(world, coord, Power.steam_power); } /** * This method is called when the block is removed from the world by an entity. */ @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()) { destroyNeighbors(w, coord, state); - ConduitRegistry.getInstance().conduitBlockRemovedEvent(w, w.dimension.getType().getId(), coord, Power.steam_power); + ConduitRegistry.getInstance().conduitBlockRemovedEvent(w, coord, Power.steam_power); } - 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){ destroyNeighbors(w,coord,w.getBlockState(coord)); - ConduitRegistry.getInstance().conduitBlockRemovedEvent(w, w.dimension.getType().getId(), coord, Power.steam_power); - super.onExplosionDestroy(w, coord, boom); + ConduitRegistry.getInstance().conduitBlockRemovedEvent(w, coord, Power.steam_power); + super.wasExploded(w, coord, boom); } private void destroyNeighbors(World w, BlockPos coord, BlockState state) { - if(w.isRemote) return; + if(w.isClientSide) return; // destroy connected drill bits for(int i = 0; i < 6; i++){ - BlockPos pos = coord.offset(Direction.byIndex(i)); - if(w.getTileEntity(pos) instanceof DrillBitTileEntity){ - DrillBitTileEntity te = (DrillBitTileEntity)w.getTileEntity(pos); + BlockPos pos = coord.relative(Direction.from3DDataValue(i)); + if(w.getBlockEntity(pos) instanceof DrillBitTileEntity){ + DrillBitTileEntity te = (DrillBitTileEntity)w.getBlockEntity(pos); te.destroyLine(); } } @@ -85,7 +85,7 @@ private void destroyNeighbors(World w, BlockPos coord, BlockState state) { * TileEntitySimplePowerConsumer. */ @Override - public PoweredEntity createNewTileEntity(final net.minecraft.world.IBlockReader world){ + public PoweredEntity newBlockEntity(final net.minecraft.world.IBlockReader world){ return new SteamDrillTileEntity(); } @@ -121,17 +121,17 @@ public boolean isPowerSource(ConduitType t){ */ @Override public BlockState getStateForPlacement(final BlockItemUseContext context) { - return this.getDefaultState().with(FACING, context.getFace().getOpposite()); + return this.defaultBlockState().setValue(FACING, context.getClickedFace().getOpposite()); } /** * Creates the blockstate of this block when it is placed in the world */ @Override - public void onBlockPlacedBy(final World world, final BlockPos coord, final BlockState bs, + public void setPlacedBy(final World world, final BlockPos coord, final BlockState bs, final LivingEntity placer, final ItemStack srcItemStack) { - if (srcItemStack.hasDisplayName()) { - final TileEntity tileEntity = world.getTileEntity(coord); + if (srcItemStack.hasCustomHoverName()) { + final TileEntity tileEntity = world.getBlockEntity(coord); if (tileEntity instanceof PoweredEntity){ ((PoweredEntity)tileEntity).setCustomInventoryName(srcItemStack.getDisplayName().getString()); } @@ -162,7 +162,7 @@ public void onBlockPlacedBy(final World world, final BlockPos coord, final Block * false otherwise */ @Override - public boolean hasComparatorInputOverride(BlockState bs){ + public boolean hasAnalogOutputSignal(BlockState bs){ return true; } @@ -183,8 +183,8 @@ public boolean hasComparatorInputOverride(BlockState bs){ * @return a number from 0 to 15 */ @Override - public int getComparatorInputOverride(BlockState bs, final World world, final BlockPos coord){ - TileEntity te = world.getTileEntity(coord); + public int getAnalogOutputSignal(BlockState bs, final World world, final BlockPos coord){ + TileEntity te = world.getBlockEntity(coord); if(te instanceof SteamDrillTileEntity){ return ((SteamDrillTileEntity)te).getComparatorOutput(); } else { @@ -196,7 +196,7 @@ public int getComparatorInputOverride(BlockState bs, final World world, final Bl * Creates a blockstate */ @Override - protected void fillStateContainer(StateContainer.Builder builder) { + protected void createBlockStateDefinition(StateContainer.Builder builder) { builder.add(FACING); } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamDrillTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamDrillTileEntity.java index 16cb299..9ea501f 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamDrillTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamDrillTileEntity.java @@ -90,7 +90,7 @@ public void tickUpdate(boolean isServerWorld) { if(progress >= progressGoal){ // Mined it! playSoundAtPosition(targetBlockCoord.getX()+0.5, targetBlockCoord.getY()+0.5, targetBlockCoord.getZ()+0.5, targetBlock.getSoundType(targetBlockState, powerAdvantageWorld(), targetBlockCoord, null).getPlaceSound(), SoundCategory.BLOCKS, 0.5f, 1f, this.powerAdvantageWorld()); - playSoundAtTileEntity( SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); + playSoundAtTileEntity( SoundEvents.FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); powerAdvantageWorld().removeBlock(targetBlockCoord, false); for(ItemStack item : targetBlockItems){ addItem(item); @@ -126,8 +126,8 @@ private boolean hasSpaceForItems(List items) { private boolean canStack(ItemStack newItem, ItemStack slot) { if(slot == null || newItem == null) return true; - return ItemStack.areItemsEqual(newItem, slot) - && ItemStack.areItemStackTagsEqual(newItem, slot) + return ItemStack.isSame(newItem, slot) + && ItemStack.tagMatches(newItem, slot) && (newItem.getCount() + slot.getCount() <= slot.getItem().getItemStackLimit(slot)); } @@ -136,8 +136,8 @@ public ItemStack addItem(ItemStack in){ if(inventory[i] == null){ inventory[i] = in; return null; - } else if(ItemStack.areItemsEqual(in, inventory[i]) - && ItemStack.areItemStackTagsEqual(in, inventory[i])){ + } else if(ItemStack.isSame(in, inventory[i]) + && ItemStack.tagMatches(in, inventory[i])){ // are stackable if(inventory[i].getCount() >= inventory[i].getItem().getItemStackLimit(inventory[i])){ continue; @@ -158,7 +158,7 @@ public ItemStack addItem(ItemStack in){ private Direction trackDirection(Direction drillDirection){ for(Direction dir : Direction.values()){ if(dir == drillDirection) continue; - if(powerAdvantageWorld().getBlockState(powerAdvantagePos().offset(dir)).getBlock() == Blocks.steam_track){ + if(powerAdvantageWorld().getBlockState(powerAdvantagePos().relative(dir)).getBlock() == Blocks.steam_track){ return dir; } } @@ -175,31 +175,31 @@ private boolean followTrack(){ this.untargetBlock(); World w = powerAdvantageWorld(); BlockPos currentPos = powerAdvantagePos(); - BlockPos nextPos = currentPos.offset(trackDir); + BlockPos nextPos = currentPos.relative(trackDir); BlockState trackState = w.getBlockState(nextPos); - w.setBlockState(nextPos, w.getBlockState(currentPos), 2); - TileEntity movedTile = w.getTileEntity(nextPos); + w.setBlock(nextPos, w.getBlockState(currentPos), 2); + TileEntity movedTile = w.getBlockEntity(nextPos); if(!(movedTile instanceof SteamDrillTileEntity)){ - w.setBlockState(nextPos, trackState, 2); + w.setBlock(nextPos, trackState, 2); return false; } SteamDrillTileEntity te = (SteamDrillTileEntity)movedTile; CompoundNBT dataTransfer = new CompoundNBT(); - this.write(dataTransfer); + this.save(dataTransfer); dataTransfer.putInt("x", nextPos.getX()); dataTransfer.putInt("y", nextPos.getY()); dataTransfer.putInt("z", nextPos.getZ()); - te.read(dataTransfer); - te.setPos(nextPos); - te.validate(); + te.load(w.getBlockState(nextPos), dataTransfer); + te.setPosition(nextPos); + te.clearRemoved(); te.subtractEnergy(ENERGY_COST_MOVE, Power.steam_power); - te.markDirty(); + te.setChanged(); Arrays.fill(this.getInventory(), null); // replace this block with steam pipe destroyDrillBit(drillDirection); - w.setBlockState(currentPos.offset(drillDirection), zone.moddev.mc.poweradvantage.init.Blocks.steel_frame.getDefaultState()); - w.setBlockState(currentPos, Blocks.steam_pipe.getDefaultState(), 2); + w.setBlockAndUpdate(currentPos.relative(drillDirection), zone.moddev.mc.poweradvantage.init.Blocks.steel_frame.defaultBlockState()); + w.setBlock(currentPos, Blocks.steam_pipe.defaultBlockState(), 2); return true; } @@ -241,7 +241,7 @@ public void onDataFieldUpdate() { Direction f = getFacing(); - BlockPos n = powerAdvantagePos().offset(f); + BlockPos n = powerAdvantagePos().relative(f); // manage drill bits and find next block if(redstone || this.getEnergy(Power.steam_power) <= 0){ @@ -260,7 +260,7 @@ public void onDataFieldUpdate() { break; } if(powerAdvantageWorld().getBlockState(n).getBlock() != Blocks.drillbit){ - if(powerAdvantageWorld().isAirBlock(n) || powerAdvantageWorld().getBlockState(n).getMaterial().isReplaceable()){ + if(powerAdvantageWorld().isEmptyBlock(n) || powerAdvantageWorld().getBlockState(n).getMaterial().isReplaceable()){ // this block is not worth mining, replace it DrillBitTileEntity.createDrillBitBlock(powerAdvantageWorld(), n, f); this.subtractEnergy(ENERGY_COST_DRILLBIT, Power.steam_power); @@ -277,7 +277,7 @@ public void onDataFieldUpdate() { break; } } - n = n.offset(f); + n = n.relative(f); if(n.getY() == 0 || n.getY() == 255){ hitEnd = true; break; @@ -288,14 +288,14 @@ public void onDataFieldUpdate() { boolean moved = followTrack(); if(moved){ zone.moddev.mc.poweradvantage.conduitnetwork.ConduitRegistry.getInstance() - .conduitBlockRemovedEvent(powerAdvantageWorld(), powerAdvantageWorld().dimension.getType().getId(), powerAdvantagePos(), Power.steam_power); + .conduitBlockRemovedEvent(powerAdvantageWorld(), powerAdvantagePos(), Power.steam_power); return; } } } else { // currently drilling a block // block validation - if(powerAdvantageWorld().isAirBlock(targetBlockCoord) || powerAdvantageWorld().getBlockState(targetBlockCoord).getBlock() != targetBlock){ + if(powerAdvantageWorld().isEmptyBlock(targetBlockCoord) || powerAdvantageWorld().getBlockState(targetBlockCoord).getBlock() != targetBlock){ // Block changed! invalidate! untargetBlock(); flagSync = true; @@ -309,17 +309,17 @@ public void onDataFieldUpdate() { // push inventory to adjacent chest - BlockPos adj = powerAdvantagePos().offset(f.getOpposite()); - if(!redstone && !powerAdvantageWorld().isAirBlock(adj)){ + BlockPos adj = powerAdvantagePos().relative(f.getOpposite()); + if(!redstone && !powerAdvantageWorld().isEmptyBlock(adj)){ inventoryTransfer(adj,f); } } private void destroyDrillBit(Direction f) { - BlockPos n = powerAdvantagePos().offset(f); + BlockPos n = powerAdvantagePos().relative(f); while(powerAdvantageWorld().getBlockState(n).getBlock() == zone.moddev.mc.steamadvantage.init.Blocks.drillbit){ powerAdvantageWorld().removeBlock(n, false); - n = n.offset(f); + n = n.relative(f); } } @@ -336,15 +336,15 @@ private void targetBlock (BlockPos n){ } else { NonNullList drops = NonNullList.create(); drops.addAll(Block.getDrops(targetBlockState, (ServerWorld) powerAdvantageWorld(), n, - powerAdvantageWorld().getTileEntity(n))); + powerAdvantageWorld().getBlockEntity(n))); targetBlockItems = drops; } deferred = false; } private void restoreTargetBlock(){ - if(powerAdvantageWorld() == null || powerAdvantageWorld().isRemote - || !powerAdvantageWorld().isBlockLoaded(targetBlockCoord)) return; + if(powerAdvantageWorld() == null || powerAdvantageWorld().isClientSide + || !powerAdvantageWorld().hasChunkAt(targetBlockCoord)) return; int savedProgress = progress; if(savedTargetState != null && !savedTargetState.equals( NBTUtil.writeBlockState(powerAdvantageWorld().getBlockState(targetBlockCoord)))){ @@ -375,8 +375,8 @@ private void untargetBlock(){ private Direction getFacing(){ BlockState state = powerAdvantageWorld().getBlockState(powerAdvantagePos()); - if(state.has(SteamDrillBlock.FACING)){ - savedFacing = state.get(SteamDrillBlock.FACING); + if(state.hasProperty(SteamDrillBlock.FACING)){ + savedFacing = state.getValue(SteamDrillBlock.FACING); return savedFacing; } if(savedFacing == null) savedFacing = inferFacing(); @@ -393,7 +393,7 @@ private Direction inferFacing(){ if(dz != 0 && dx == 0 && dy == 0) return dz > 0 ? Direction.SOUTH : Direction.NORTH; } for(Direction dir : Direction.values()){ - if(powerAdvantageWorld().getBlockState(powerAdvantagePos().offset(dir)).getBlock() == Blocks.drillbit){ + if(powerAdvantageWorld().getBlockState(powerAdvantagePos().relative(dir)).getBlock() == Blocks.drillbit){ return dir; } } @@ -407,7 +407,7 @@ private void energyDecay() { } private boolean hasRedstoneSignal() { - return powerAdvantageWorld().isBlockPowered(powerAdvantagePos()); + return powerAdvantageWorld().hasNeighborSignal(powerAdvantagePos()); } private boolean canMine(BlockPos coord){ @@ -416,18 +416,18 @@ private boolean canMine(BlockPos coord){ } private int getBlockStrength(BlockPos coord){ - if(powerAdvantageWorld().isAirBlock(coord)){ + if(powerAdvantageWorld().isEmptyBlock(coord)){ return 0; } BlockState bs = powerAdvantageWorld().getBlockState(coord); Block block = bs.getBlock(); - return (int)(Math.max(MINING_TIME_FACTOR * block.getBlockHardness(bs,powerAdvantageWorld(), coord),0.5f * MINING_TIME_FACTOR)); + return (int)(Math.max(MINING_TIME_FACTOR * bs.getDestroySpeed(powerAdvantageWorld(), coord),0.5f * MINING_TIME_FACTOR)); } private void inventoryTransfer(BlockPos adj, Direction otherFace) { - TileEntity te = powerAdvantageWorld().getTileEntity(adj); + TileEntity te = powerAdvantageWorld().getBlockEntity(adj); if(te instanceof IInventory ){ ISidedInventory inv = InventoryWrapper.wrap((IInventory)te); int[] accessibleSlots = inv.getSlotsForFace(otherFace); @@ -436,26 +436,26 @@ private void inventoryTransfer(BlockPos adj, Direction otherFace) { if(this.inventory[mySlot] == null || this.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; } } @@ -466,12 +466,12 @@ private void inventoryTransfer(BlockPos adj, Direction otherFace) { } @Override - public CompoundNBT write(CompoundNBT tagRoot){ - super.write(tagRoot); + public CompoundNBT save(CompoundNBT tagRoot){ + super.save(tagRoot); tagRoot.putShort("progress",(short)progress); // getFacing refreshes this during normal ticks. World lookups here can // synchronously reload a chunk while its unload-save is in progress. - if(savedFacing != null) tagRoot.putByte("Facing", (byte)savedFacing.getIndex()); + if(savedFacing != null) tagRoot.putByte("Facing", (byte)savedFacing.get3DDataValue()); if(targetBlockCoord != null){ tagRoot.putInt("targetX", targetBlockCoord.getX()); tagRoot.putInt("targetY", targetBlockCoord.getY()); @@ -482,15 +482,15 @@ public CompoundNBT write(CompoundNBT tagRoot){ } @Override - public void read(CompoundNBT tagRoot){ - super.read(tagRoot); + public void load(net.minecraft.block.BlockState state, CompoundNBT tagRoot){ + super.load(state, tagRoot); untargetBlock(); savedFacing = null; oldDir = null; if(tagRoot.contains("Facing")){ int facingIndex = tagRoot.getByte("Facing"); if(facingIndex >= 0 && facingIndex < Direction.values().length){ - savedFacing = Direction.byIndex(facingIndex); + savedFacing = Direction.from3DDataValue(facingIndex); } } if(tagRoot.contains("progress")){ @@ -540,7 +540,7 @@ public boolean isPowerSource(ConduitType conduitType) { } @Override - public boolean isUsableByPlayer(PlayerEntity player) { + public boolean stillValid(PlayerEntity player) { return true; } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamElevatorBlock.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamElevatorBlock.java index 6bb7fb4..01c652e 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamElevatorBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamElevatorBlock.java @@ -21,19 +21,19 @@ public SteamElevatorBlock() { } @Override - public PoweredEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public PoweredEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new SteamElevatorTileEntity(); } @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 SteamElevatorTileEntity){ - return ((SteamElevatorTileEntity)world.getTileEntity(coord)).getComparatorOutput(); + public int getAnalogOutputSignal(BlockState bs, World world, BlockPos coord) { + if(world.getBlockEntity(coord) instanceof SteamElevatorTileEntity){ + return ((SteamElevatorTileEntity)world.getBlockEntity(coord)).getComparatorOutput(); } return 0; } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamElevatorTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamElevatorTileEntity.java index 8f57751..8240537 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamElevatorTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamElevatorTileEntity.java @@ -26,7 +26,7 @@ public class SteamElevatorTileEntity extends cyano.poweradvantage.api.simple.Til private final int[] dataSyncArray = new int[1]; - private boolean up = false; + private boolean above = false; public SteamElevatorTileEntity() { super(zone.moddev.mc.steamadvantage.init.Entities.STEAM_ELEVATOR, Power.steam_power, STEAM_PER_ELEVATOR_MOVE*2, "tile.steamadvantage.steam_elevator.name"); @@ -39,11 +39,11 @@ public void tickUpdate(boolean isServerWorld) { if(isServerWorld){ // controlled by redstone - if(redstone != up){ + if(redstone != above){ if(redstone) { - up = moveUp(); + above = moveUp(); } else { - up = !moveDown(); + above = !moveDown(); } } } @@ -52,34 +52,34 @@ public void tickUpdate(boolean isServerWorld) { private boolean moveUp(){ if(this.getEnergy(Power.steam_power) < STEAM_PER_ELEVATOR_MOVE) return false; this.subtractEnergy(STEAM_PER_ELEVATOR_MOVE, Power.steam_power); - playSoundAtTileEntity( SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); - playSoundAtTileEntity( SoundEvents.BLOCK_PISTON_EXTEND, SoundCategory.BLOCKS, 0.5f, 1f, this); + playSoundAtTileEntity( SoundEvents.FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); + playSoundAtTileEntity( SoundEvents.PISTON_EXTEND, SoundCategory.BLOCKS, 0.5f, 1f, this); int dist = 0; - BlockPos p = this.getPos().up(); - while(p.getY() < 256 && dist < MAX_RANGE && getWorld().isAirBlock(p)){ + BlockPos p = this.getBlockPos().above(); + while(p.getY() < 256 && dist < MAX_RANGE && getLevel().isEmptyBlock(p)){ dist++; - p = p.up(); + p = p.above(); } - BlockPos topPos = p.down(2); - p = p.down(3); // make room for character to stand in + BlockPos topPos = p.below(2); + p = p.below(3); // make room for character to stand in boolean top = true; - for(; p.getY() > getPos().getY(); p = p.down()){ + for(; p.getY() > getBlockPos().getY(); p = p.below()){ if(top){ // platform top - getWorld().setBlockState(p, Blocks.steam_elevator_platforms[4]); + getLevel().setBlockAndUpdate(p, Blocks.steam_elevator_platforms[4]); top = false; } else { // shaft - getWorld().setBlockState(p, Blocks.steam_elevator_platforms[0]); + getLevel().setBlockAndUpdate(p, Blocks.steam_elevator_platforms[0]); } } // move people - List passengers = getWorld().getEntitiesWithinAABB(Entity.class, - new AxisAlignedBB(getPos().getX(),getPos().getY()+1,getPos().getZ(), - getPos().getX()+1, topPos.getY(), getPos().getZ()+1)); + List passengers = getLevel().getEntitiesOfClass(Entity.class, + new AxisAlignedBB(getBlockPos().getX(),getBlockPos().getY()+1,getBlockPos().getZ(), + getBlockPos().getX()+1, topPos.getY(), getBlockPos().getZ()+1)); for(Entity e : passengers){ - e.setPositionAndUpdate(e.getPosX(),topPos.getY()+smallAmount, e.getPosZ()); + e.teleportTo(e.getX(),topPos.getY()+smallAmount, e.getZ()); e.fallDistance = 0; } return true; @@ -88,25 +88,25 @@ private boolean moveUp(){ private boolean moveDown(){ if(this.getEnergy(Power.steam_power) < STEAM_PER_ELEVATOR_MOVE) return false; this.subtractEnergy(STEAM_PER_ELEVATOR_MOVE, Power.steam_power); - playSoundAtTileEntity( SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); - playSoundAtTileEntity( SoundEvents.BLOCK_PISTON_CONTRACT, SoundCategory.BLOCKS, 0.5f, 1f, this); + playSoundAtTileEntity( SoundEvents.FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); + playSoundAtTileEntity( SoundEvents.PISTON_CONTRACT, SoundCategory.BLOCKS, 0.5f, 1f, this); // scan up the piston and clear it - BlockPos destination = this.getPos().up(); + BlockPos destination = this.getBlockPos().above(); BlockPos p = destination; - while(getWorld().getBlockState(p).getBlock() == Blocks.steam_elevator_platform){ - p = p.up(); + while(getLevel().getBlockState(p).getBlock() == Blocks.steam_elevator_platform){ + p = p.above(); } // remove piston - BlockPos i = p.down(); - for(; i.getY() > getPos().getY(); i = i.down()){ - getWorld().removeBlock(i, false); + BlockPos i = p.below(); + for(; i.getY() > getBlockPos().getY(); i = i.below()){ + getLevel().removeBlock(i, false); } // move people - List passengers = getWorld().getEntitiesWithinAABB(Entity.class, + List passengers = getLevel().getEntitiesOfClass(Entity.class, new AxisAlignedBB(p.getX(),p.getY(),p.getZ(), p.getX()+1, p.getY()+2, p.getZ()+1)); for(Entity e : passengers){ - e.setPositionAndUpdate(e.getPosX(), destination.getY()+smallAmount,e.getPosZ()); + e.teleportTo(e.getX(), destination.getY()+smallAmount,e.getZ()); e.fallDistance = 0; } return true; @@ -131,7 +131,7 @@ public void powerUpdate(){ private boolean hasRedstoneSignal() { - return getWorld().isBlockPowered(getPos()); + return getLevel().hasNeighborSignal(getBlockPos()); } @@ -151,7 +151,7 @@ public int[] getDataFieldArray() { @Override public void prepareDataFieldsForSync() { - if(up){ + if(above){ dataSyncArray[0] = 1; } else { dataSyncArray[0] = 0; @@ -160,31 +160,31 @@ public void prepareDataFieldsForSync() { @Override public void onDataFieldUpdate() { - this.up = dataSyncArray[0] != 0; + this.above = dataSyncArray[0] != 0; } @Override - public CompoundNBT write(CompoundNBT tagRoot){ - super.write(tagRoot); - tagRoot.putBoolean("up",up); + public CompoundNBT save(CompoundNBT tagRoot){ + super.save(tagRoot); + tagRoot.putBoolean("up",above); return tagRoot; } @Override - public void read(CompoundNBT tagRoot){ - super.read(tagRoot); + public void load(net.minecraft.block.BlockState state, CompoundNBT tagRoot){ + super.load(state, tagRoot); if(tagRoot.contains("up")){ - up = tagRoot.getBoolean("up"); + above = tagRoot.getBoolean("up"); } } public int getComparatorOutput() { - if(up) return 15; + if(above) return 15; return 0; } @@ -200,7 +200,7 @@ public boolean isPowerSource(ConduitType conduitType) { } @Override - public boolean isUsableByPlayer(PlayerEntity player) { + public boolean stillValid(PlayerEntity player) { return true; } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamPumpBlock.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamPumpBlock.java index e318960..cab9bf8 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamPumpBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamPumpBlock.java @@ -27,19 +27,19 @@ public SteamPumpBlock() { } @Override - public PoweredEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public PoweredEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new SteamPumpTileEntity(); } @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 SteamPumpTileEntity){ - return ((SteamPumpTileEntity)world.getTileEntity(coord)).getComparatorOutput(); + public int getAnalogOutputSignal(BlockState bs, World world, BlockPos coord) { + if(world.getBlockEntity(coord) instanceof SteamPumpTileEntity){ + return ((SteamPumpTileEntity)world.getBlockEntity(coord)).getComparatorOutput(); } return 0; } @@ -57,25 +57,25 @@ public boolean isPowerSource(ConduitType type){ return !ConduitType.areSameType(Power.steam_power, type); } @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); } @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_steam){ w.removeBlock(c, false); - c = c.down(); + c = c.below(); } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamPumpTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamPumpTileEntity.java index 850a189..e8d0ab8 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamPumpTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamPumpTileEntity.java @@ -63,29 +63,29 @@ public void tickUpdate(boolean isServerWorld) { if(!redstone){ 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.steamadvantage.init.Blocks.pump_pipe_steam){ - target = target.down(); + target = target.below(); } - if(target.getY() > 0 && w.isAirBlock(target) && getEnergy(Power.steam_power) >= ENERGY_COST_PIPE){ + if(target.getY() > 0 && w.isEmptyBlock(target) && getEnergy(Power.steam_power) >= ENERGY_COST_PIPE){ // place pipe - w.setBlockState(target, zone.moddev.mc.steamadvantage.init.Blocks.pump_pipe_steam.getDefaultState()); + w.setBlockAndUpdate(target, zone.moddev.mc.steamadvantage.init.Blocks.pump_pipe_steam.defaultBlockState()); this.subtractEnergy(ENERGY_COST_PIPE, Power.steam_power); timeUntilNextPump = PIPE_INTERVAL; - playSoundAtTileEntity( SoundEvents.BLOCK_STONE_PLACE, SoundCategory.BLOCKS, 0.3f, 1f, this); + playSoundAtTileEntity( SoundEvents.STONE_PLACE, SoundCategory.BLOCKS, 0.3f, 1f, this); } 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); @@ -99,15 +99,15 @@ public void tickUpdate(boolean isServerWorld) { timeUntilNextPump = PUMP_INTERVAL; } if(success){ - playSoundAtTileEntity( SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); - playSoundAtTileEntity( SoundEvents.BLOCK_PISTON_EXTEND, SoundCategory.BLOCKS, 0.3f, 1f, this); + playSoundAtTileEntity( SoundEvents.FIRE_EXTINGUISH, SoundCategory.AMBIENT, 0.5f, 1f, this); + playSoundAtTileEntity( SoundEvents.PISTON_EXTEND, SoundCategory.BLOCKS, 0.3f, 1f, this); timeToSound = 14; } } } if(timeToSound == 1){ - playSoundAtTileEntity( SoundEvents.BLOCK_PISTON_CONTRACT, SoundCategory.BLOCKS, 0.3f, 1f, this); - playSoundAtTileEntity( SoundEvents.ITEM_BUCKET_FILL, SoundCategory.BLOCKS, 1f, 1f, this); + playSoundAtTileEntity( SoundEvents.PISTON_CONTRACT, SoundCategory.BLOCKS, 0.3f, 1f, this); + playSoundAtTileEntity( SoundEvents.BUCKET_FILL, SoundCategory.BLOCKS, 1f, 1f, this); } if(timeToSound > 0) timeToSound--; energyDecay(); @@ -117,7 +117,7 @@ public void tickUpdate(boolean isServerWorld) { private Fluid getFluid(BlockState blockstate) { - return blockstate.getFluidState().isEmpty() ? null : blockstate.getFluidState().getFluid(); + return blockstate.getFluidState().isEmpty() ? null : blockstate.getFluidState().getType(); } @@ -132,7 +132,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; @@ -148,21 +148,21 @@ 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(); } private boolean hasRedstoneSignal() { - return getWorld().isBlockPowered(getPos()); + return getLevel().hasNeighborSignal(getBlockPos()); } @@ -184,7 +184,7 @@ public void powerUpdate(){ ConduitType type = Fluids.fluidToConduitType(fluid.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! } else { @@ -192,8 +192,8 @@ public void powerUpdate(){ for(int i = 1; i < Direction.values().length; i++){ if(getTank().getFluidAmount() <= 0) break; Direction dir = Direction.values()[i]; - BlockPos nPos = getPos().offset(dir); - TileEntity neighbor = getWorld().getTileEntity(nPos); + BlockPos nPos = getBlockPos().relative(dir); + TileEntity neighbor = getLevel().getBlockEntity(nPos); IAdvantageFluidHandler handler = FluidHandlerHelper.getHandler(neighbor, dir.getOpposite()); if(handler != null){ int d = handler.fill(dir.getOpposite(), fluid, true); @@ -266,8 +266,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); @@ -279,8 +279,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(net.minecraft.block.BlockState state, final CompoundNBT tagRoot) { + super.load(state, tagRoot); String tankKey = tagRoot.contains("Tank") ? "Tank" : "TankOut"; if (tagRoot.contains(tankKey)) { CompoundNBT tankTag = tagRoot.getCompound(tankKey); @@ -442,14 +442,14 @@ public FluidTankInfo[] getTankInfo(Direction face) { ///// end of IFluidHandler methods ///// @Override - public boolean isItemValidForSlot(final int slot, final ItemStack item) { + public boolean canPlaceItem(final int slot, final ItemStack item) { return false; // no inventory } @Override - public boolean isUsableByPlayer(PlayerEntity player) { + public boolean stillValid(PlayerEntity player) { return true; } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamStillBlock.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamStillBlock.java index 2087cb5..54611ef 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamStillBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamStillBlock.java @@ -26,19 +26,19 @@ public SteamStillBlock() { } @Override - public PoweredEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public PoweredEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new SteamStillTileEntity(); } @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 SteamStillTileEntity){ - return ((SteamStillTileEntity)world.getTileEntity(coord)).getComparatorOutput(); + public int getAnalogOutputSignal(BlockState bs, World world, BlockPos coord) { + if(world.getBlockEntity(coord) instanceof SteamStillTileEntity){ + return ((SteamStillTileEntity)world.getBlockEntity(coord)).getComparatorOutput(); } return 0; } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamStillTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamStillTileEntity.java index 28ff12b..31d8520 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamStillTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamStillTileEntity.java @@ -57,7 +57,7 @@ && canDistill(getInputTank().getFluid())){ distill(); this.subtractEnergy(steamPerDistill, Power.steam_power); if(timeSinceSound > 200){ - playSoundAtTileEntity(SoundEvents.BLOCK_LAVA_AMBIENT, SoundCategory.AMBIENT, 0.3f, 1.5f, this); + playSoundAtTileEntity(SoundEvents.LAVA_AMBIENT, SoundCategory.AMBIENT, 0.3f, 1.5f, this); timeSinceSound = 0; } timeSinceSound++; @@ -70,7 +70,7 @@ && canDistill(getInputTank().getFluid())){ private boolean hasRedstoneSignal() { - return getWorld().isBlockPowered(getPos()); + return getLevel().hasNeighborSignal(getBlockPos()); } @@ -92,7 +92,7 @@ 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, - this.getMinimumSinkPriority(), getWorld(), getPos(), this); + this.getMinimumSinkPriority(), getLevel(), getBlockPos(), this); if(delta > 0){ getOutputTank().drain(Math.max((int)delta,1),true); // no free energy! } @@ -172,8 +172,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.getOutputTank().writeToNBT(tankTag); tagRoot.put("TankOut", tankTag); @@ -187,8 +187,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(net.minecraft.block.BlockState state, final CompoundNBT tagRoot) { + super.load(state, tagRoot); if (tagRoot.contains("TankOut")) { CompoundNBT tankTag = tagRoot.getCompound("TankOut"); getOutputTank().readFromNBT(tankTag); @@ -420,12 +420,12 @@ public FluidTankInfo[] getTankInfo(Direction face) { ///// end of IFluidHandler methods ///// @Override - public boolean isItemValidForSlot(final int slot, final ItemStack item) { + public boolean canPlaceItem(final int slot, final ItemStack item) { return false; // no inventory } @Override - public boolean isUsableByPlayer(PlayerEntity player) { + public boolean stillValid(PlayerEntity player) { return true; } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamTankBlock.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamTankBlock.java index 9c3f526..966bbbf 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamTankBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamTankBlock.java @@ -16,18 +16,18 @@ public SteamTankBlock(){ } @Override - public PoweredEntity createNewTileEntity(net.minecraft.world.IBlockReader world) { + public PoweredEntity newBlockEntity(net.minecraft.world.IBlockReader world) { return new SteamTankTileEntity(); } @Override - public boolean hasComparatorInputOverride(BlockState bs) { + public boolean hasAnalogOutputSignal(BlockState bs) { return true; } @Override - public int getComparatorInputOverride(BlockState bs, World world, BlockPos coord) { - TileEntity te = world.getTileEntity(coord); + public int getAnalogOutputSignal(BlockState bs, World world, BlockPos coord) { + TileEntity te = world.getBlockEntity(coord); if(te instanceof SteamTankTileEntity){ return (int)(15 * ((SteamTankTileEntity)te).getSteamLevel()); } else{ diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamTankTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamTankTileEntity.java index 565362b..1cac8fb 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamTankTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamTankTileEntity.java @@ -54,7 +54,7 @@ protected float transmitPowerToConsumers(float amount, ConduitType type, byte pr } private boolean hasRedstoneSignal() { - return getWorld().isBlockPowered(getPos()); + return getLevel().hasNeighborSignal(getBlockPos()); } @@ -116,7 +116,7 @@ public float getSteamLevel(){ } @Override - public boolean isUsableByPlayer(PlayerEntity player) { + public boolean stillValid(PlayerEntity player) { return true; } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/migration/SteamLegacyMigrations.java b/src/main/java/zone/moddev/mc/steamadvantage/migration/SteamLegacyMigrations.java index a7e1c02..fd9e157 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/migration/SteamLegacyMigrations.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/migration/SteamLegacyMigrations.java @@ -58,10 +58,10 @@ private static void registerTile(String path) { private static BlockState decodeState(Block block, int metadata) { if (block instanceof SteamDrillBlock) { - return block.getDefaultState().with(SteamDrillBlock.FACING, legacyDrillFacing(metadata)); + return block.defaultBlockState().setValue(SteamDrillBlock.FACING, legacyDrillFacing(metadata)); } if (block instanceof PlatformBlock) { - return block.getDefaultState().with(PlatformBlock.HEIGHT, + return block.defaultBlockState().setValue(PlatformBlock.HEIGHT, Integer.valueOf(legacyPlatformHeight(metadata))); } if (block instanceof BlockPowerSwitch) { @@ -70,11 +70,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 % Direction.values().length); + return Direction.from3DDataValue(metadata % Direction.values().length); } static int legacyPlatformHeight(int metadata) { diff --git a/src/main/java/zone/moddev/mc/steamadvantage/recipe/RecipeConditions.java b/src/main/java/zone/moddev/mc/steamadvantage/recipe/RecipeConditions.java index 056984d..7994d45 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/recipe/RecipeConditions.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/recipe/RecipeConditions.java @@ -22,7 +22,7 @@ public static synchronized void register() { CraftingHelper.register(new IConditionSerializer() { @Override public ResourceLocation getID() { return ModeCondition.ID; } @Override public ModeCondition read(JsonObject json) { - return new ModeCondition(RecipeMode.valueOf(JSONUtils.getString(json, "mode").toUpperCase(Locale.ROOT))); + return new ModeCondition(RecipeMode.valueOf(JSONUtils.getAsString(json, "mode").toUpperCase(Locale.ROOT))); } @Override public void write(JsonObject json, ModeCondition condition) { json.addProperty("mode", condition.mode.name()); diff --git a/src/main/java/zone/moddev/mc/steamadvantage/util/FurnaceFuelHelper.java b/src/main/java/zone/moddev/mc/steamadvantage/util/FurnaceFuelHelper.java index 2920f87..4e91d3a 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/util/FurnaceFuelHelper.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/util/FurnaceFuelHelper.java @@ -1,21 +1,13 @@ package zone.moddev.mc.steamadvantage.util; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.tileentity.AbstractFurnaceTileEntity; -import net.minecraftforge.event.ForgeEventFactory; +import net.minecraftforge.common.ForgeHooks; /** Forge-aware access to the vanilla furnace fuel calculation. */ public final class FurnaceFuelHelper { private FurnaceFuelHelper() {} public static int getBurnTime(ItemStack stack) { - if (stack.isEmpty()) return 0; - Item item = stack.getItem(); - int itemBurnTime = stack.getBurnTime(); - int vanillaBurnTime = itemBurnTime == -1 - ? AbstractFurnaceTileEntity.getBurnTimes().getOrDefault(item, 0) - : itemBurnTime; - return ForgeEventFactory.getItemBurnTime(stack, vanillaBurnTime); + return ForgeHooks.getBurnTime(stack, null); } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/util/SoundHelper.java b/src/main/java/zone/moddev/mc/steamadvantage/util/SoundHelper.java index 59c8580..169fbf4 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/util/SoundHelper.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/util/SoundHelper.java @@ -7,7 +7,7 @@ import net.minecraft.util.SoundEvent; import net.minecraft.util.math.AxisAlignedBB; 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; @@ -15,32 +15,32 @@ public class SoundHelper { public static void playSoundAtTileEntity(SoundEvent sound, SoundCategory soundType, float volume, float pitch, TileEntity te){ - final BlockPos pos = te.getPos(); - final Vec3d center = new Vec3d(pos.getX()+0.5,pos.getY()+0.5,pos.getZ()+0.5); - playSoundAtPosition(center.x, center.y, center.z, sound, soundType, volume, pitch, te.getWorld()); + final BlockPos pos = te.getBlockPos(); + final Vector3d center = new Vector3d(pos.getX()+0.5,pos.getY()+0.5,pos.getZ()+0.5); + playSoundAtPosition(center.x, center.y, center.z, sound, soundType, volume, pitch, te.getLevel()); } public static void playSoundAtPosition(double x, double y, double z, SoundEvent sound, SoundCategory soundType, float volume, float pitch, World serverWorld){ - if(serverWorld.isRemote) return; + if(serverWorld.isClientSide) return; final double range = 16; - List players = serverWorld.getEntitiesWithinAABB(ServerPlayerEntity.class, new AxisAlignedBB( + List players = serverWorld.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(), soundType, - new Vec3d(x, y, z), volume, pitch)); + player.connection.send(new SPlaySoundPacket(sound.getRegistryName(), soundType, + new Vector3d(x, y, z), volume, pitch)); } } public static void playBigSoundAtPosition(double x, double y, double z, SoundEvent sound, SoundCategory soundType, float volume, float pitch, World serverWorld){ - if(serverWorld.isRemote) return; + if(serverWorld.isClientSide) return; final double range = 50; - List players = serverWorld.getEntitiesWithinAABB(ServerPlayerEntity.class, new AxisAlignedBB( + List players = serverWorld.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(), soundType, - new Vec3d(x, y, z), volume, pitch)); + player.connection.send(new SPlaySoundPacket(sound.getRegistryName(), soundType, + new Vector3d(x, y, z), volume, pitch)); } } } diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 2ee02b0..676ecd8 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -14,14 +14,14 @@ description='''Steam-powered machines and infrastructure for the Power Advantage [[dependencies.steamadvantage]] 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.steamadvantage]] 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 e8e4d16..9adca15 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":"Steam Advantage" } } diff --git a/src/test/java/zone/moddev/mc/steamadvantage/blocks/DrillBitPersistenceTest.java b/src/test/java/zone/moddev/mc/steamadvantage/blocks/DrillBitPersistenceTest.java index 5fa588d..69b15ba 100644 --- a/src/test/java/zone/moddev/mc/steamadvantage/blocks/DrillBitPersistenceTest.java +++ b/src/test/java/zone/moddev/mc/steamadvantage/blocks/DrillBitPersistenceTest.java @@ -6,27 +6,31 @@ import static org.junit.Assert.*; public class DrillBitPersistenceTest { + @org.junit.BeforeClass public static void bootstrapNativeRegistries() { + net.minecraft.util.registry.Bootstrap.bootStrap(); + } + @Test public void allSixDirectionsSurviveNativeUpdatePackets() { for (Direction direction : Direction.values()) { DrillBitTileEntity tile = new DrillBitTileEntity(); tile.setDirection(direction); - CompoundNBT packet = tile.getUpdatePacket().getNbtCompound(); - assertEquals(direction.getIndex(), packet.getByte("dir")); + CompoundNBT packet = tile.getUpdatePacket().getTag(); + assertEquals(direction.get3DDataValue(), packet.getByte("dir")); DrillBitTileEntity restored = new DrillBitTileEntity(); restored.onDataPacket(null, tile.getUpdatePacket()); assertEquals(direction.getAxis(), restored.getDirection()); - assertEquals(direction.getIndex(), restored.getUpdatePacket().getNbtCompound().getByte("dir")); + assertEquals(direction.get3DDataValue(), restored.getUpdatePacket().getTag().getByte("dir")); } } @Test public void oldDirectionKeyRemainsReadableAndCanonicalKeyWins() { CompoundNBT tag = new CompoundNBT(); - tag.putByte("d", (byte) Direction.EAST.getIndex()); + tag.putByte("d", (byte) Direction.EAST.get3DDataValue()); DrillBitTileEntity tile = new DrillBitTileEntity(); - tile.read(tag); + tile.load(net.minecraft.block.Blocks.AIR.defaultBlockState(), tag); assertEquals(Direction.Axis.X, tile.getDirection()); - tag.putByte("dir", (byte) Direction.NORTH.getIndex()); - tile.read(tag); + tag.putByte("dir", (byte) Direction.NORTH.get3DDataValue()); + tile.load(net.minecraft.block.Blocks.AIR.defaultBlockState(), tag); assertEquals(Direction.Axis.Z, tile.getDirection()); } @@ -34,7 +38,7 @@ public class DrillBitPersistenceTest { CompoundNBT tag = new CompoundNBT(); tag.putByte("dir", (byte) 127); DrillBitTileEntity tile = new DrillBitTileEntity(); - tile.read(tag); - assertEquals(Direction.DOWN.getIndex(), tile.getUpdatePacket().getNbtCompound().getByte("dir")); + tile.load(net.minecraft.block.Blocks.AIR.defaultBlockState(), tag); + assertEquals(Direction.DOWN.get3DDataValue(), tile.getUpdatePacket().getTag().getByte("dir")); } } diff --git a/src/test/java/zone/moddev/mc/steamadvantage/graphics/DrillBitRendererTest.java b/src/test/java/zone/moddev/mc/steamadvantage/graphics/DrillBitRendererTest.java index d4d0be4..27bf46d 100644 --- a/src/test/java/zone/moddev/mc/steamadvantage/graphics/DrillBitRendererTest.java +++ b/src/test/java/zone/moddev/mc/steamadvantage/graphics/DrillBitRendererTest.java @@ -17,9 +17,9 @@ public class DrillBitRendererTest { for (Direction facing : Direction.values()) { RecordingBuffer buffer = new RecordingBuffer(); MatrixStack matrices = new MatrixStack(); - MatrixStack.Entry caller = matrices.getLast(); + MatrixStack.Entry caller = matrices.last(); DrillBitRenderer.renderGeometry(facing.getAxis(), 0, matrices, buffer, LIGHT, OVERLAY); - assertSame(caller, matrices.getLast()); + assertSame(caller, matrices.last()); assertEquals(24, buffer.vertices.size()); double[] minimum = { Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY }; double[] maximum = { Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY }; @@ -59,7 +59,7 @@ public class DrillBitRendererTest { @Test public void failedVertexSubmissionRestoresTheCallerMatrix() { MatrixStack matrices = new MatrixStack(); - MatrixStack.Entry caller = matrices.getLast(); + MatrixStack.Entry caller = matrices.last(); try { DrillBitRenderer.renderGeometry(Direction.Axis.X, 37, matrices, new RecordingBuffer() { @Override public void endVertex() { throw new IllegalStateException("submission failed"); } @@ -68,7 +68,7 @@ public class DrillBitRendererTest { } catch (IllegalStateException expected) { assertEquals("submission failed", expected.getMessage()); } - assertSame(caller, matrices.getLast()); + assertSame(caller, matrices.last()); } private static final class Vertex { @@ -83,7 +83,7 @@ private static class RecordingBuffer implements IVertexBuilder { final List vertices = new ArrayList<>(); private Vertex vertex = new Vertex(); - @Override public IVertexBuilder pos(double x, double y, double z) { + @Override public IVertexBuilder vertex(double x, double y, double z) { vertex.position[0] = x; vertex.position[1] = y; vertex.position[2] = z; return this; } @@ -91,9 +91,9 @@ private static class RecordingBuffer implements IVertexBuilder { vertex.color[0] = red; vertex.color[1] = green; vertex.color[2] = blue; vertex.color[3] = alpha; return this; } - @Override public IVertexBuilder tex(float u, float v) { vertex.u = u; vertex.v = 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.u = u; vertex.v = 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[0] = x; vertex.normal[1] = y; vertex.normal[2] = z; return this; diff --git a/src/test/java/zone/moddev/mc/steamadvantage/items/MusketPersistenceTest.java b/src/test/java/zone/moddev/mc/steamadvantage/items/MusketPersistenceTest.java index 8a491f5..875a5a5 100644 --- a/src/test/java/zone/moddev/mc/steamadvantage/items/MusketPersistenceTest.java +++ b/src/test/java/zone/moddev/mc/steamadvantage/items/MusketPersistenceTest.java @@ -3,14 +3,14 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import org.junit.Test; import org.junit.BeforeClass; import static org.junit.Assert.*; public class MusketPersistenceTest { @BeforeClass public static void bootstrapNativeRegistries() { - net.minecraft.util.registry.Bootstrap.register(); + net.minecraft.util.registry.Bootstrap.bootStrap(); } @Test public void loadingCycleKeepsLegacyByteValuesAndOtherNbt() { @@ -32,10 +32,10 @@ public class MusketPersistenceTest { } @Test public void rayIntersectionSupportsEveryAxisAndRejectsTargetsBehind() { - Vec3d origin = new Vec3d(0, 0, 0); + Vector3d origin = new Vector3d(0, 0, 0); for (net.minecraft.util.Direction direction : net.minecraft.util.Direction.values()) { - Vec3d ray = new Vec3d(direction.getXOffset(), direction.getYOffset(), direction.getZOffset()); - Vec3d center = ray.scale(5); + Vector3d ray = new Vector3d(direction.getStepX(), direction.getStepY(), direction.getStepZ()); + Vector3d center = ray.scale(5); AxisAlignedBB ahead = new AxisAlignedBB(center.x - 0.5, center.y - 0.5, center.z - 0.5, center.x + 0.5, center.y + 0.5, center.z + 0.5); assertTrue(MusketItem.rayIntersectsBoundingBox(origin, ray, ahead)); diff --git a/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamDrillPersistenceTest.java b/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamDrillPersistenceTest.java index 6fd6c4f..699107e 100644 --- a/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamDrillPersistenceTest.java +++ b/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamDrillPersistenceTest.java @@ -25,20 +25,20 @@ public class SteamDrillPersistenceTest { @BeforeClass public static void bootstrapNativeRegistries() { - net.minecraft.util.registry.Bootstrap.register(); + net.minecraft.util.registry.Bootstrap.bootStrap(); } @Test public void retainsLegacyProgressUntilWorldIsAttached() { SteamDrillTileEntity drill = new SteamDrillTileEntity(); - drill.read(target(94)); + drill.load(net.minecraft.block.Blocks.AIR.defaultBlockState(), target(94)); drill.prepareDataFieldsForSync(); assertEquals(94, drill.getDataFieldArray()[1]); } @Test public void clearsPreviousProgressOnReadingAnUntargetedTile() { SteamDrillTileEntity drill = new SteamDrillTileEntity(); - drill.read(target(94)); - drill.read(new CompoundNBT()); + drill.load(net.minecraft.block.Blocks.AIR.defaultBlockState(), target(94)); + drill.load(net.minecraft.block.Blocks.AIR.defaultBlockState(), new CompoundNBT()); drill.prepareDataFieldsForSync(); assertEquals(0, drill.getDataFieldArray()[1]); } @@ -46,12 +46,12 @@ public class SteamDrillPersistenceTest { @Test public void preservesAllSixFacingsTargetAndWorkUntilWorldIsAttached() throws Exception { for (Direction facing : Direction.values()) { CompoundNBT tag = target(94); - tag.putByte("Facing", (byte) facing.getIndex()); + tag.putByte("Facing", (byte) facing.get3DDataValue()); CompoundNBT state = new CompoundNBT(); state.putString("Name", "minecraft:stone"); tag.put("TargetState", state); SteamDrillTileEntity drill = new SteamDrillTileEntity(); - drill.read(tag); + drill.load(net.minecraft.block.Blocks.AIR.defaultBlockState(), tag); assertEquals(facing, field(drill, "savedFacing")); assertEquals(new BlockPos(2048, 80, 2049), field(drill, "targetBlockCoord")); assertEquals(state, field(drill, "savedTargetState")); @@ -64,12 +64,12 @@ public class SteamDrillPersistenceTest { @Test public void loadingAnotherTileDoesNotKeepPreviousFacing() throws Exception { SteamDrillTileEntity drill = new SteamDrillTileEntity(); CompoundNBT tag = target(94); - tag.putByte("Facing", (byte) Direction.UP.getIndex()); - drill.read(tag); - drill.read(target(12)); + tag.putByte("Facing", (byte) Direction.UP.get3DDataValue()); + drill.load(net.minecraft.block.Blocks.AIR.defaultBlockState(), tag); + drill.load(net.minecraft.block.Blocks.AIR.defaultBlockState(), target(12)); assertNull(field(drill, "savedFacing")); tag.putByte("Facing", (byte) 127); - drill.read(tag); + drill.load(net.minecraft.block.Blocks.AIR.defaultBlockState(), tag); assertNull(field(drill, "savedFacing")); } @@ -84,9 +84,9 @@ public class SteamDrillPersistenceTest { items.add(stack); tag.put("Items", items); SteamDrillTileEntity drill = new SteamDrillTileEntity(); - drill.read(tag); + drill.load(net.minecraft.block.Blocks.AIR.defaultBlockState(), tag); assertEquals(37.5F, drill.getEnergy(Power.steam_power), 0.0F); - ItemStack output = drill.getStackInSlot(4); + ItemStack output = drill.getItem(4); assertEquals(net.minecraft.item.Items.COBBLESTONE, output.getItem()); assertEquals(23, output.getCount()); } @@ -98,7 +98,7 @@ public class SteamDrillPersistenceTest { } int methods = 0, cachedFacingReads = 0; for (MethodNode method : node.methods) { - if (!method.name.equals("write")) continue; + if (!method.name.equals("save")) continue; methods++; for (AbstractInsnNode instruction : method.instructions.toArray()) { if (instruction instanceof FieldInsnNode @@ -120,13 +120,13 @@ public class SteamDrillPersistenceTest { BlockPos origin = new BlockPos(2048, 80, 2048); for (Direction direction : Direction.values()) { CompoundNBT tag = target(94); - BlockPos target = origin.offset(direction, 3); + BlockPos target = origin.relative(direction, 3); tag.putInt("targetX", target.getX()); tag.putInt("targetY", target.getY()); tag.putInt("targetZ", target.getZ()); SteamDrillTileEntity drill = new SteamDrillTileEntity(); - drill.read(tag); - drill.setPos(origin); + drill.load(net.minecraft.block.Blocks.AIR.defaultBlockState(), tag); + drill.setPosition(origin); assertNull(field(drill, "savedFacing")); assertEquals(direction, infer.invoke(drill)); } diff --git a/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamMachinePersistenceTest.java b/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamMachinePersistenceTest.java new file mode 100644 index 0000000..1b424db --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamMachinePersistenceTest.java @@ -0,0 +1,146 @@ +package zone.moddev.mc.steamadvantage.machines; + +import cyano.poweradvantage.api.fluid.FluidStack; +import java.util.function.Supplier; +import net.minecraft.block.Blocks; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.ForgeRegistry; +import org.junit.BeforeClass; +import org.junit.Test; +import zone.moddev.mc.steamadvantage.init.Entities; +import zone.moddev.mc.steamadvantage.init.Power; +import static org.junit.Assert.*; + +public class SteamMachinePersistenceTest { + @BeforeClass public static void bootstrapNativeTypes() { + net.minecraft.util.registry.Bootstrap.bootStrap(); + Entities.STEAM_BOILER_COAL = type("steam_boiler_coal", CoalBoilerTileEntity::new); + Entities.STEAM_BOILER_ELECTRIC = type("steam_boiler_electric", ElectricBoilerTileEntity::new); + Entities.STEAM_BOILER_GEOTHERMAL = type("steam_boiler_geothermal", GeothermalBoilerTileEntity::new); + Entities.STEAM_PUMP = type("steam_pump", SteamPumpTileEntity::new); + Entities.STEAM_STILL = type("steam_still", SteamStillTileEntity::new); + Entities.STEAM_TANK = type("steam_tank", SteamTankTileEntity::new); + } + + @Test public void levelsAndDecayRetainExactBinaryFractions() { + CoalBoilerTileEntity coal = new CoalBoilerTileEntity(); + coal.setEnergy(375.0F, Power.steam_power); + coal.getTank().fill(new FluidStack(net.minecraft.fluid.Fluids.WATER, 1500), true); + assertEquals(0.375F, coal.getSteamLevel(), 0.0F); + assertEquals(0.375F, coal.getWaterLevel(), 0.0F); + ElectricBoilerTileEntity electric = new ElectricBoilerTileEntity(); + electric.setEnergy(37.5F, Power.steam_power); + electric.setEnergy(60.0F, ElectricBoilerTileEntity.ELECTRIC_POWER); + assertEquals(0.375F, electric.getSteamLevel(), 0.0F); + assertEquals(0.375F, electric.getElectricityLevel(), 0.0F); + SteamTankTileEntity tank = new SteamTankTileEntity(); + tank.setEnergy(3750.0F, Power.steam_power); + assertEquals(0.375F, tank.getSteamLevel(), 0.0F); + tank.tickUpdate(true); + assertEquals(3749.9375F, tank.getEnergy(Power.steam_power), 0.0F); + assertEquals(0.0625F, Power.ENERGY_LOST_PER_TICK, 0.0F); + assertEquals(0.03125F, ElectricBoilerTileEntity.ELECTRICITY_TO_STEAM, 0.0F); + assertEquals(2.5F, SteamDrillTileEntity.ENERGY_COST_DRILLBIT, 0.0F); + assertEquals(10.0F, SteamDrillTileEntity.ENERGY_COST_MOVE, 0.0F); + assertEquals(1.0F, SteamDrillTileEntity.ENERGY_COST_PROGRESS_TICK, 0.0F); + assertEquals(32.0F, SteamElevatorTileEntity.STEAM_PER_ELEVATOR_MOVE, 0.0F); + assertEquals(125, RockCrusherTileEntity.TICKS_PER_ACTION); + } + + @Test public void coalAndElectricStateSurviveNativeSaveLoad() { + CompoundNBT tag = state(37.5F); + tag.put("Tank", water(1500)); + tag.putInt("BurnTime", 127); + tag.putInt("BurnTimeTotal", 1600); + CoalBoilerTileEntity coal = new CoalBoilerTileEntity(); + coal.load(Blocks.AIR.defaultBlockState(), tag); + CompoundNBT saved = coal.save(new CompoundNBT()); + assertEquals("steamadvantage:steam_boiler_coal", saved.getString("id")); + assertEquals(127, saved.getInt("BurnTime")); + assertEquals(1600, saved.getInt("BurnTimeTotal")); + CoalBoilerTileEntity restored = new CoalBoilerTileEntity(); + restored.load(Blocks.AIR.defaultBlockState(), saved); + assertEquals(37.5F, restored.getEnergy(Power.steam_power), 0.0F); + assertEquals(1500, restored.getTank().getFluidAmount()); + tag.putFloat("Electricity", 60.0F); + ElectricBoilerTileEntity electric = new ElectricBoilerTileEntity(); + electric.load(Blocks.AIR.defaultBlockState(), tag); + ElectricBoilerTileEntity electricRestored = new ElectricBoilerTileEntity(); + electricRestored.load(Blocks.AIR.defaultBlockState(), electric.save(new CompoundNBT())); + assertEquals(37.5F, electricRestored.getEnergy(Power.steam_power), 0.0F); + assertEquals(60.0F, electricRestored.getEnergy(ElectricBoilerTileEntity.ELECTRIC_POWER), 0.0F); + assertEquals(1500, electricRestored.getTank().getFluidAmount()); + } + + @Test public void pumpAliasAndGeothermalMisspellingRemainReadable() { + CompoundNBT tag = state(37.5F); + tag.put("TankOut", water(750)); + tag.putByte("NextPump", (byte) 11); + SteamPumpTileEntity pump = new SteamPumpTileEntity(); + pump.load(Blocks.AIR.defaultBlockState(), tag); + CompoundNBT saved = pump.save(new CompoundNBT()); + assertEquals(750, saved.getCompound("Tank").getInt("Amount")); + assertEquals(11, saved.getByte("NextPump")); + SteamPumpTileEntity pumpRestored = new SteamPumpTileEntity(); + pumpRestored.load(Blocks.AIR.defaultBlockState(), saved); + assertEquals(750, pumpRestored.getTank().getFluidAmount()); + assertEquals(37.5F, pumpRestored.getEnergy(Power.steam_power), 0.0F); + tag.putFloat("Tempoerature", 412.5F); + GeothermalBoilerTileEntity geothermal = new GeothermalBoilerTileEntity(); + geothermal.load(Blocks.AIR.defaultBlockState(), tag); + assertEquals(412.5F, geothermal.save(new CompoundNBT()).getFloat("Temperature"), 0.0F); + tag.putFloat("Temperature", 500.0F); + geothermal.load(Blocks.AIR.defaultBlockState(), tag); + assertEquals(500.0F, geothermal.save(new CompoundNBT()).getFloat("Temperature"), 0.0F); + } + + @Test public void stillKeepsSeparateTanksAndExplicitlyEmptyReloads() { + CompoundNBT tag = state(37.5F); + tag.put("TankIn", water(625)); + tag.put("TankOut", water(375)); + SteamStillTileEntity still = new SteamStillTileEntity(); + still.load(Blocks.AIR.defaultBlockState(), tag); + SteamStillTileEntity restored = new SteamStillTileEntity(); + restored.load(Blocks.AIR.defaultBlockState(), still.save(new CompoundNBT())); + assertEquals(625, restored.getInputTank().getFluidAmount()); + assertEquals(375, restored.getOutputTank().getFluidAmount()); + assertEquals(37.5F, restored.getEnergy(Power.steam_power), 0.0F); + tag.put("TankIn", water(0)); + tag.put("TankOut", water(0)); + restored.load(Blocks.AIR.defaultBlockState(), tag); + assertEquals(0, restored.getInputTank().getFluidAmount()); + assertEquals(0, restored.getOutputTank().getFluidAmount()); + } + + private static CompoundNBT state(float steam) { + CompoundNBT tag = new CompoundNBT(); + tag.putIntArray("Energy", new int[] {Float.floatToIntBits(steam)}); + return tag; + } + + private static CompoundNBT water(int amount) { + CompoundNBT tag = new CompoundNBT(); + tag.putString("FluidName", "minecraft:water"); + tag.putInt("Amount", amount); + return tag; + } + + private static TileEntityType type(String id, Supplier factory) { + ForgeRegistry> registry = + (ForgeRegistry>) ForgeRegistries.TILE_ENTITIES; + boolean locked = registry.isLocked(); + registry.unfreeze(); + try { + TileEntityType type = TileEntityType.Builder.of(factory, Blocks.STONE).build(null); + type.setRegistryName(new ResourceLocation("steamadvantage", id)); + registry.register(type); + return type; + } finally { + if (locked) registry.freeze(); + } + } +} diff --git a/src/test/java/zone/moddev/mc/steamadvantage/migration/SteamLegacyMigrationsTest.java b/src/test/java/zone/moddev/mc/steamadvantage/migration/SteamLegacyMigrationsTest.java index 6df1471..088b40f 100644 --- a/src/test/java/zone/moddev/mc/steamadvantage/migration/SteamLegacyMigrationsTest.java +++ b/src/test/java/zone/moddev/mc/steamadvantage/migration/SteamLegacyMigrationsTest.java @@ -12,7 +12,7 @@ public class SteamLegacyMigrationsTest { @Test public void preservesAllSixDrillFacings() { for (Direction facing : Direction.values()) { - assertEquals(facing, SteamLegacyMigrations.legacyDrillFacing(facing.getIndex())); + assertEquals(facing, SteamLegacyMigrations.legacyDrillFacing(facing.get3DDataValue())); } } diff --git a/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java index 6a0863a..5d2f7e4 100644 --- a/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java @@ -11,9 +11,15 @@ public class BuildWorkflowContractTest { for (String name : new String[] {"ci.yml", "codeql-analysis.yml"}) { String source = new String(Files.readAllBytes(Paths.get(".github/workflows", name)), StandardCharsets.UTF_8); - assertTrue(name, source.contains("ref: ac1781e7cade15045ffe0135077087b4d1722603")); - assertTrue(name, source.contains("BaseMetals-3.0.2.115021-deobf.jar")); - assertTrue(name, source.contains("ref: 6666099a734eba16561d98c86f3f4bb1b7c742f7")); + assertTrue(name, source.contains("ref: 995f6cc4dd2d5eecc628a42e5c43fa5390c24bca")); + assertTrue(name, source.contains("BaseMetals-3.1.1.116051-deobf.jar")); + assertTrue(name, source.contains("ref: a113e5d767169189f0e35ade1e173a12d550b00e")); + assertTrue(name, source.contains("ref: 098d4625abc8a849bd1a11dcf697b3fee0cade7b")); + assertTrue(name, source.contains("Final Power 1.16 dependency pin is pending.")); + assertTrue(name, source.contains("^[a-f0-9]{40}$")); + assertTrue(name, source.contains("^[A-F0-9]{64}$")); + assertTrue(name, source.indexOf("Validate final Power source pin") + < source.indexOf("Check out PowerAdvantage 1.16.5")); assertTrue(name, source.contains("-Porg.gradle.java.installations.paths=")); assertTrue(name, source.contains("-Porg.gradle.java.installations.auto-detect=false")); assertTrue(name, source.contains("-Porg.gradle.java.installations.auto-download=false")); diff --git a/src/test/java/zone/moddev/mc/steamadvantage/resources/NativeBlockPropertiesTest.java b/src/test/java/zone/moddev/mc/steamadvantage/resources/NativeBlockPropertiesTest.java index 903f882..4f56087 100644 --- a/src/test/java/zone/moddev/mc/steamadvantage/resources/NativeBlockPropertiesTest.java +++ b/src/test/java/zone/moddev/mc/steamadvantage/resources/NativeBlockPropertiesTest.java @@ -35,20 +35,20 @@ public static Collection cases() { @Parameterized.Parameter(1) public int height; private Block block; - @BeforeClass public static void bootstrapNativeRegistries() { Bootstrap.register(); } + @BeforeClass public static void bootstrapNativeRegistries() { Bootstrap.bootStrap(); } @Before public void createNativeBlockAndStateCaches() { block = height < 0 ? new SteamTrackBlock() : new PlatformBlock(); - for (BlockState state : block.getStateContainer().getValidStates()) state.cacheState(); + for (BlockState state : block.getStateDefinition().getPossibleStates()) state.initCache(); } @Test public void remainsNonSolid() { - for (BlockState state : states()) assertFalse(state.toString(), state.isSolid()); + for (BlockState state : states()) assertFalse(state.toString(), state.canOcclude()); } @Test public void remainsNonOpaque() { for (BlockState state : states()) { - assertFalse(state.toString(), state.isOpaqueCube(EmptyBlockReader.INSTANCE, BlockPos.ZERO)); + assertFalse(state.toString(), state.isSolidRender(EmptyBlockReader.INSTANCE, BlockPos.ZERO)); } } @@ -56,40 +56,56 @@ public static Collection cases() { // Native opacity is 1, not 0, for a non-solid block with a full-cube outline. int expected = height < 0 || height == 4 ? 1 : 0; for (BlockState state : states()) { - assertEquals(state.toString(), expected, state.getOpacity(EmptyBlockReader.INSTANCE, BlockPos.ZERO)); + assertEquals(state.toString(), expected, state.getLightBlock(EmptyBlockReader.INSTANCE, BlockPos.ZERO)); } } @Test public void remainsANonNormalCube() { for (BlockState state : states()) { - assertFalse(state.toString(), state.isNormalCube(EmptyBlockReader.INSTANCE, BlockPos.ZERO)); + assertFalse(state.toString(), state.isRedstoneConductor(EmptyBlockReader.INSTANCE, BlockPos.ZERO)); } } @Test public void doesNotConductWeakPowerOnAnyFace() { for (BlockState state : states()) { for (Direction face : Direction.values()) { - // The native hook delegates to isNormalCube; these constant shapes need no world lookup. + // The native hook delegates to isRedstoneConductor; these constant shapes need no world lookup. assertFalse(state + " face=" + face, state.shouldCheckWeakPower(null, BlockPos.ZERO, face)); } } } + @Test public void retainsExactNativeStrengthAndHarvestLevel() { + for (BlockState state : states()) { + assertEquals(height < 0 ? 0.75F : 5.0F, + state.getDestroySpeed(EmptyBlockReader.INSTANCE, BlockPos.ZERO), 0.0F); + assertEquals(-1, state.getHarvestLevel()); + assertNull(state.getHarvestTool()); + } + } + + @Test public void fullCollisionHelpersNeitherSuffocateNorBlockTheView() { + for (BlockState state : states()) { + assertFalse(state.toString(), state.isSuffocating(EmptyBlockReader.INSTANCE, BlockPos.ZERO)); + assertFalse(state.toString(), state.isViewBlocking(EmptyBlockReader.INSTANCE, BlockPos.ZERO)); + } + } + @Test public void preservesOutlineAndCollisionShapes() { - VoxelShape expected = height < 0 || height == 4 ? VoxelShapes.fullCube() - : height == 0 ? VoxelShapes.create(0.25D, 0.0D, 0.25D, 0.75D, 1.0D, 0.75D) - : VoxelShapes.create(0.0D, 0.0D, 0.0D, 1.0D, height * 0.25D, 1.0D); + VoxelShape expected = height < 0 || height == 4 ? VoxelShapes.block() + : height == 0 ? VoxelShapes.box(0.25D, 0.0D, 0.25D, 0.75D, 1.0D, 0.75D) + : VoxelShapes.box(0.0D, 0.0D, 0.0D, 1.0D, height * 0.25D, 1.0D); if (height < 0) assertEquals(64, states().size()); for (BlockState state : states()) { - assertFalse(state + " outline", VoxelShapes.compare(expected, + assertFalse(state + " outline", VoxelShapes.joinIsNotEmpty(expected, state.getShape(EmptyBlockReader.INSTANCE, BlockPos.ZERO), IBooleanFunction.NOT_SAME)); - assertFalse(state + " collision", VoxelShapes.compare(expected, + assertFalse(state + " collision", VoxelShapes.joinIsNotEmpty(expected, state.getCollisionShape(EmptyBlockReader.INSTANCE, BlockPos.ZERO), IBooleanFunction.NOT_SAME)); } } private Collection states() { - return height < 0 ? block.getStateContainer().getValidStates() - : Collections.singletonList(block.getDefaultState().with(PlatformBlock.HEIGHT, height)); + return height < 0 ? block.getStateDefinition().getPossibleStates() + : Collections.singletonList(block.defaultBlockState().setValue(PlatformBlock.HEIGHT, height)); } } diff --git a/src/test/java/zone/moddev/mc/steamadvantage/resources/NativeFuelContractTest.java b/src/test/java/zone/moddev/mc/steamadvantage/resources/NativeFuelContractTest.java new file mode 100644 index 0000000..89a65d7 --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/resources/NativeFuelContractTest.java @@ -0,0 +1,57 @@ +package zone.moddev.mc.steamadvantage.resources; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.item.crafting.IRecipeType; +import net.minecraft.resources.ResourcePackType; +import net.minecraft.resources.SimpleReloadableResourceManager; +import net.minecraft.resources.VanillaPack; +import net.minecraft.tags.ITagCollection; +import net.minecraft.tags.ITagCollectionSupplier; +import net.minecraft.tags.TagCollectionManager; +import net.minecraft.tags.TagCollectionReader; +import net.minecraft.tags.TagRegistryManager; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.registry.Registry; +import net.minecraftforge.common.ForgeHooks; +import org.junit.BeforeClass; +import org.junit.Test; +import zone.moddev.mc.steamadvantage.util.FurnaceFuelHelper; +import static org.junit.Assert.*; + +public class NativeFuelContractTest { + @BeforeClass public static void bootstrapNativeFuel() { + net.minecraft.util.registry.Bootstrap.bootStrap(); + // Standalone tests need the actual vanilla item tags before the native fuel map. + try (SimpleReloadableResourceManager resources = + new SimpleReloadableResourceManager(ResourcePackType.SERVER_DATA)) { + resources.add(new VanillaPack("minecraft")); + TagCollectionReader reader = + new TagCollectionReader<>(Registry.ITEM::getOptional, "tags/items", "item"); + ITagCollection items = reader.load(reader.prepare(resources, Runnable::run).join()); + assertTrue(items.getAllTags().containsKey(new ResourceLocation("minecraft:non_flammable_wood"))); + ITagCollectionSupplier current = TagCollectionManager.getInstance(); + TagRegistryManager.get(new ResourceLocation("minecraft:item")).reset( + ITagCollectionSupplier.of(current.getBlocks(), items, + current.getFluids(), current.getEntityTypes())); + } + ForgeHooks.updateBurns(); + } + + @Test public void keepsExactVanillaAndEmptyFuelValues() { + assertEquals(0, FurnaceFuelHelper.getBurnTime(ItemStack.EMPTY)); + assertEquals(1600, FurnaceFuelHelper.getBurnTime(new ItemStack(Items.COAL))); + assertEquals(20000, FurnaceFuelHelper.getBurnTime(new ItemStack(Items.LAVA_BUCKET))); + } + + @Test public void retainsTheForgeItemBurnTimeOverride() { + Item item = new Item(new Item.Properties()) { + @Override public int getBurnTime(ItemStack stack, IRecipeType recipeType) { + assertNull(recipeType); + return 237; + } + }; + assertEquals(237, FurnaceFuelHelper.getBurnTime(new ItemStack(item))); + } +} diff --git a/src/test/java/zone/moddev/mc/steamadvantage/resources/NativeLootContractTest.java b/src/test/java/zone/moddev/mc/steamadvantage/resources/NativeLootContractTest.java index 6dae7f5..f6b4075 100644 --- a/src/test/java/zone/moddev/mc/steamadvantage/resources/NativeLootContractTest.java +++ b/src/test/java/zone/moddev/mc/steamadvantage/resources/NativeLootContractTest.java @@ -39,8 +39,8 @@ public class NativeLootContractTest { } } - @Test public void packUsesNative115Format() throws Exception { - assertEquals(5, read(ROOT.resolve("pack.mcmeta")).getAsJsonObject("pack").get("pack_format").getAsInt()); + @Test public void packUsesNative116Format() throws Exception { + assertEquals(6, read(ROOT.resolve("pack.mcmeta")).getAsJsonObject("pack").get("pack_format").getAsInt()); } private static JsonObject read(Path path) throws Exception { diff --git a/src/test/java/zone/moddev/mc/steamadvantage/resources/RecipeRegistrationThreadTest.java b/src/test/java/zone/moddev/mc/steamadvantage/resources/RecipeRegistrationThreadTest.java index e900e10..20b6b22 100644 --- a/src/test/java/zone/moddev/mc/steamadvantage/resources/RecipeRegistrationThreadTest.java +++ b/src/test/java/zone/moddev/mc/steamadvantage/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/src/test/java/zone/moddev/mc/steamadvantage/resources/WorldOnlyConduitContractTest.java b/src/test/java/zone/moddev/mc/steamadvantage/resources/WorldOnlyConduitContractTest.java new file mode 100644 index 0000000..afdcf8b --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/resources/WorldOnlyConduitContractTest.java @@ -0,0 +1,36 @@ +package zone.moddev.mc.steamadvantage.resources; + +import java.io.InputStream; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import static org.junit.Assert.*; + +public class WorldOnlyConduitContractTest { + @Test public void everyDrillCallbackUsesTheWorldOnlyParentOverload() throws Exception { + int callbacks = 0; + for (String type : new String[] {"SteamDrillBlock", "SteamDrillTileEntity"}) { + ClassNode node = new ClassNode(); + try (InputStream input = getClass().getResourceAsStream( + "/zone/moddev/mc/steamadvantage/machines/" + type + ".class")) { + assertNotNull(input); + new ClassReader(input).accept(node, 0); + } + for (MethodNode method : node.methods) { + for (AbstractInsnNode instruction : method.instructions.toArray()) { + if (!(instruction instanceof MethodInsnNode)) continue; + MethodInsnNode call = (MethodInsnNode) instruction; + if (!call.owner.equals("zone/moddev/mc/poweradvantage/conduitnetwork/ConduitRegistry") + || !call.name.startsWith("conduitBlock")) continue; + assertTrue(type + "." + method.name + call.desc, + call.desc.startsWith("(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;")); + callbacks++; + } + } + } + assertEquals(4, callbacks); + } +} From 7f55f9d9389bfa26adefb66e07a45f39a6f2e897 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 14:03:34 +0000 Subject: [PATCH 2/9] Pin Steam 1.16.5 verification to Power C --- .github/workflows/ci.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- README.md | 25 ++++++++++--------- build.gradle | 4 +-- gradle.properties | 6 ++--- .../resources/BuildWorkflowContractTest.java | 2 +- 6 files changed, 21 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc70ab1..540515d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,7 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/PowerAdvantage - 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 610b46b..2eca472 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -51,7 +51,7 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/PowerAdvantage - ref: 098d4625abc8a849bd1a11dcf697b3fee0cade7b + ref: e72fc3c39dab98fe2fb7b6a9105e0173585d6001 path: .ci-dependencies/PowerAdvantage - name: Install pinned Java 25 Mavenizer runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 diff --git a/README.md b/README.md index 3b5d982..b797725 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # SteamAdvantage **Minecraft 1.16.5 port candidate, version 2.2.8.116051.** -This branch is local work pending full verification and manual acceptance. -No 1.16 gameplay, rendering, or world-upgrade -qualification is claimed. Accepted 1.15 results do not qualify this candidate. +This branch is a local candidate pending manual acceptance and publication approval. +Build, test, and runtime evidence is tied to exact dependency pins; none establishes +complete gameplay or world-upgrade qualification. Accepted 1.15 results do not +qualify this candidate. Steam Advantage adds steam-powered machines and infrastructure to Power Advantage. @@ -15,18 +16,18 @@ ForgeGradle 7.0.34 and Gradle 9.6.1 run on Temurin 17.0.1+12. Compilation and Minecraft launches use Temurin 8.0.502+7 and Java 8 bytecode; Mavenizer uses Temurin 25.0.3+9.0.LTS. -Power Advantage 2.4.7.116051 remains a separate required mod. The stable local API -bootstrap B source is `098d4625abc8a849bd1a11dcf697b3fee0cade7b`; its development jar SHA-256 is -`78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3`. +Power Advantage 2.4.7.116051 remains a separate required mod. The current local +candidate is Power C, source `e72fc3c39dab98fe2fb7b6a9105e0173585d6001`. +Its development jar SHA-256 is +`C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B`. These exact pins are recorded in `gradle.properties` and audited during builds. Use an immutable development jar through `-PpowerAdvantageDeobfJar=`. -This API bootstrap is not runtime qualification and may be repinned after runtime -fixes. Release audits reject missing or placeholder pins. +Release audits reject missing, placeholder, or mismatched pins. These source pins +are local candidates, not publication approval. -Steam's 87-test build and artifact evidence belongs to bootstrap A, not B. -Bootstrap B initializes the GUI matrix before legacy direct decoration calls. -Steam compilation and the full suite against B remain pending the next cache -lease. Neither bootstrap has Steam runtime or manual acceptance. +Earlier A/B build receipts and D runtime evidence remain historical evidence for +their original inputs. They do not qualify the C candidate. Automated build and +test results, bounded runtime checks, and manual acceptance are separate gates. The supplied native development dependencies are Base Metals 3.1.1.116051 (source `995f6cc4dd2d5eecc628a42e5c43fa5390c24bca`) and OreSpawn 4.1.0.116051 diff --git a/build.gradle b/build.gradle index 65e4447..72cfe62 100644 --- a/build.gradle +++ b/build.gradle @@ -378,8 +378,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') } String mainSource = file( diff --git a/gradle.properties b/gradle.properties index 594d478..c4218a0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -37,9 +37,9 @@ cf_versions=1.16.5 poweradvantage_version=2.4.7.116051 poweradvantage_source_repository=MinecraftModDevelopmentMods/PowerAdvantage -# Bootstrap B: native GUI matrix initialization; Steam B verification is pending. -poweradvantage_source_ref=098d4625abc8a849bd1a11dcf697b3fee0cade7b -poweradvantage_deobf_sha256=78E58DD2AB04E2B9F3267E5735C64AAE7E93EAC97571CB04485038862C853ED3 +# Power C local candidate; automated verification and manual acceptance are separate. +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/steamadvantage/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java index 5d2f7e4..f9de150 100644 --- a/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java @@ -14,7 +14,7 @@ public class BuildWorkflowContractTest { assertTrue(name, source.contains("ref: 995f6cc4dd2d5eecc628a42e5c43fa5390c24bca")); assertTrue(name, source.contains("BaseMetals-3.1.1.116051-deobf.jar")); assertTrue(name, source.contains("ref: a113e5d767169189f0e35ade1e173a12d550b00e")); - assertTrue(name, source.contains("ref: 098d4625abc8a849bd1a11dcf697b3fee0cade7b")); + assertTrue(name, source.contains("ref: e72fc3c39dab98fe2fb7b6a9105e0173585d6001")); assertTrue(name, source.contains("Final Power 1.16 dependency pin is pending.")); assertTrue(name, source.contains("^[a-f0-9]{40}$")); assertTrue(name, source.contains("^[A-F0-9]{64}$")); From 362048a513267fae47ed9cfa187f08b97726d40b Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 15:39:52 +0000 Subject: [PATCH 3/9] Pin Steam 1.16.5 verification to Power D --- .github/workflows/ci.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- README.md | 11 ++++++----- build.gradle | 4 ++-- gradle.properties | 6 +++--- .../resources/BuildWorkflowContractTest.java | 2 +- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 540515d..89ef2b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,7 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/PowerAdvantage - 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 2eca472..0f4201f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -51,7 +51,7 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/PowerAdvantage - ref: e72fc3c39dab98fe2fb7b6a9105e0173585d6001 + ref: 2116a35a40dd150d79e7dfdcdc891637793178b7 path: .ci-dependencies/PowerAdvantage - name: Install pinned Java 25 Mavenizer runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 diff --git a/README.md b/README.md index b797725..07b525f 100644 --- a/README.md +++ b/README.md @@ -17,17 +17,18 @@ Compilation and Minecraft launches use Temurin 8.0.502+7 and Java 8 bytecode; Mavenizer uses Temurin 25.0.3+9.0.LTS. Power Advantage 2.4.7.116051 remains a separate required mod. The current local -candidate is Power C, source `e72fc3c39dab98fe2fb7b6a9105e0173585d6001`. +candidate is Power D, source `2116a35a40dd150d79e7dfdcdc891637793178b7`. Its development jar SHA-256 is -`C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B`. +`F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A`. These exact pins are recorded in `gradle.properties` and audited during builds. Use an immutable development jar through `-PpowerAdvantageDeobfJar=`. Release audits reject missing, placeholder, or mismatched pins. These source pins are local candidates, not publication approval. -Earlier A/B build receipts and D runtime evidence remain historical evidence for -their original inputs. They do not qualify the C candidate. Automated build and -test results, bounded runtime checks, and manual acceptance are separate gates. +Earlier dependency-candidate build and runtime receipts remain historical evidence +for their original inputs. They do not qualify the current candidate. Automated +build and test results, bounded runtime checks, and manual acceptance are separate +gates. The supplied native development dependencies are Base Metals 3.1.1.116051 (source `995f6cc4dd2d5eecc628a42e5c43fa5390c24bca`) and OreSpawn 4.1.0.116051 diff --git a/build.gradle b/build.gradle index 72cfe62..15db3ca 100644 --- a/build.gradle +++ b/build.gradle @@ -378,8 +378,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') } String mainSource = file( diff --git a/gradle.properties b/gradle.properties index c4218a0..1aef4e7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -37,9 +37,9 @@ cf_versions=1.16.5 poweradvantage_version=2.4.7.116051 poweradvantage_source_repository=MinecraftModDevelopmentMods/PowerAdvantage -# Power C local candidate; automated verification and manual acceptance are separate. -poweradvantage_source_ref=e72fc3c39dab98fe2fb7b6a9105e0173585d6001 -poweradvantage_deobf_sha256=C97CE8428480AF34595428F439013F517CB9024092CD8475D56AFBEB8E6F497B +# Power D local candidate; automated verification and manual acceptance are separate. +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/steamadvantage/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java index f9de150..c6bf939 100644 --- a/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java @@ -14,7 +14,7 @@ public class BuildWorkflowContractTest { assertTrue(name, source.contains("ref: 995f6cc4dd2d5eecc628a42e5c43fa5390c24bca")); assertTrue(name, source.contains("BaseMetals-3.1.1.116051-deobf.jar")); assertTrue(name, source.contains("ref: a113e5d767169189f0e35ade1e173a12d550b00e")); - assertTrue(name, source.contains("ref: e72fc3c39dab98fe2fb7b6a9105e0173585d6001")); + assertTrue(name, source.contains("ref: 2116a35a40dd150d79e7dfdcdc891637793178b7")); assertTrue(name, source.contains("Final Power 1.16 dependency pin is pending.")); assertTrue(name, source.contains("^[a-f0-9]{40}$")); assertTrue(name, source.contains("^[A-F0-9]{64}$")); From b820801e8959a0383af36fc7fb4d38f30ebc1e1b Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 18:06:52 +0000 Subject: [PATCH 4/9] Pin Power E candidate for Steam 1.16.5 --- .github/workflows/ci.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- CHANGELOG.txt | 2 +- README.md | 4 ++-- build.gradle | 4 ++-- gradle.properties | 6 +++--- .../steamadvantage/resources/BuildWorkflowContractTest.java | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89ef2b1..bcfd8ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,7 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/PowerAdvantage - 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 0f4201f..92a3f91 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -51,7 +51,7 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/PowerAdvantage - 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 f4f685e..91a07ce 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -8,7 +8,7 @@ Steam Advantage 2.2.8.116051 (local port candidate) - Preserve registry identities, recipe and trade quantities, machine ratios and NBT. - Retain exact track/platform opacity, collision and redstone behavior. - Add exact native level, persistence and callback regressions. -- Pin Power's stable local API bootstrap; keep 1.16 runtime/manual qualification pending. +- Pin Power Advantage local candidate E; keep current-input runtime and manual qualification pending. Steam Advantage 2.2.7.115021 diff --git a/README.md b/README.md index 07b525f..fdd5d9b 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,9 @@ Compilation and Minecraft launches use Temurin 8.0.502+7 and Java 8 bytecode; Mavenizer uses Temurin 25.0.3+9.0.LTS. Power Advantage 2.4.7.116051 remains a separate required mod. The current local -candidate is Power D, source `2116a35a40dd150d79e7dfdcdc891637793178b7`. +candidate is Power E, source `3f1100e6f75b1fb949cc883be7288aa30789876d`. Its development jar SHA-256 is -`F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A`. +`1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4`. These exact pins are recorded in `gradle.properties` and audited during builds. Use an immutable development jar through `-PpowerAdvantageDeobfJar=`. Release audits reject missing, placeholder, or mismatched pins. These source pins diff --git a/build.gradle b/build.gradle index 15db3ca..ffa0d04 100644 --- a/build.gradle +++ b/build.gradle @@ -378,8 +378,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') } String mainSource = file( diff --git a/gradle.properties b/gradle.properties index 1aef4e7..782c292 100644 --- a/gradle.properties +++ b/gradle.properties @@ -37,9 +37,9 @@ cf_versions=1.16.5 poweradvantage_version=2.4.7.116051 poweradvantage_source_repository=MinecraftModDevelopmentMods/PowerAdvantage -# Power D local candidate; automated verification and manual acceptance are separate. -poweradvantage_source_ref=2116a35a40dd150d79e7dfdcdc891637793178b7 -poweradvantage_deobf_sha256=F58B93DAF03CF303F32B18CCCA140E55E886A2BA82732A3F286ADF3E31194B6A +# Power E local candidate; automated verification and manual acceptance are separate. +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/steamadvantage/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java index c6bf939..2e66e59 100644 --- a/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java @@ -14,7 +14,7 @@ public class BuildWorkflowContractTest { assertTrue(name, source.contains("ref: 995f6cc4dd2d5eecc628a42e5c43fa5390c24bca")); assertTrue(name, source.contains("BaseMetals-3.1.1.116051-deobf.jar")); assertTrue(name, source.contains("ref: a113e5d767169189f0e35ade1e173a12d550b00e")); - assertTrue(name, source.contains("ref: 2116a35a40dd150d79e7dfdcdc891637793178b7")); + assertTrue(name, source.contains("ref: 3f1100e6f75b1fb949cc883be7288aa30789876d")); assertTrue(name, source.contains("Final Power 1.16 dependency pin is pending.")); assertTrue(name, source.contains("^[a-f0-9]{40}$")); assertTrue(name, source.contains("^[A-F0-9]{64}$")); From 9a26bd3b6191e5aa3244cc2a4193342890c8d3e7 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 19:45:08 +0000 Subject: [PATCH 5/9] Update the 1.16 build and testing notes --- CHANGELOG.txt | 4 +++- README.md | 13 +++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 91a07ce..079ab5b 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -8,7 +8,9 @@ Steam Advantage 2.2.8.116051 (local port candidate) - Preserve registry identities, recipe and trade quantities, machine ratios and NBT. - Retain exact track/platform opacity, collision and redstone behavior. - Add exact native level, persistence and callback regressions. -- Pin Power Advantage local candidate E; keep current-input runtime and manual qualification pending. +- Pin the Power Advantage build that preserves legacy Forge swimming-speed values and modifiers during upgrades. +- Pass all 87 Java tests with Gradle and the Eclipse compiler, along with release and Eclipse audits. +- Recheck connected-machine upgrades, recipes, mining and full-restart operation through the shared Advantage Works rig; keep wider migration checks and manual acceptance separate. Steam Advantage 2.2.7.115021 diff --git a/README.md b/README.md index fdd5d9b..b46cefb 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,14 @@ **Minecraft 1.16.5 port candidate, version 2.2.8.116051.** This branch is a local candidate pending manual acceptance and publication approval. -Build, test, and runtime evidence is tied to exact dependency pins; none establishes -complete gameplay or world-upgrade qualification. Accepted 1.15 results do not -qualify this candidate. +All 87 Java tests pass with Gradle and the Eclipse compiler, along with release +and Eclipse audits. Combined machine, recipe, mining and connected-world upgrade +checks pass against the pinned jars; wider migration checks are still being +completed. Accepted 1.15 results do not qualify this candidate. + +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. Steam Advantage adds steam-powered machines and infrastructure to Power Advantage. @@ -17,7 +22,7 @@ Compilation and Minecraft launches use Temurin 8.0.502+7 and Java 8 bytecode; Mavenizer uses Temurin 25.0.3+9.0.LTS. Power Advantage 2.4.7.116051 remains a separate required mod. The current local -candidate is Power E, source `3f1100e6f75b1fb949cc883be7288aa30789876d`. +candidate uses source `3f1100e6f75b1fb949cc883be7288aa30789876d`. Its development jar SHA-256 is `1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4`. These exact pins are recorded in `gradle.properties` and audited during builds. From 5be1ce9faf7465d072f2c8b0e3206899bafb34e8 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 20:20:40 +0000 Subject: [PATCH 6/9] Pin Power F candidate for Steam 1.16.5 --- .github/workflows/ci.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- CHANGELOG.txt | 4 ++-- README.md | 14 +++++++++----- build.gradle | 4 ++-- gradle.properties | 6 +++--- .../resources/BuildWorkflowContractTest.java | 13 ++++++++++++- 7 files changed, 30 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bcfd8ac..6806ff9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,7 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/PowerAdvantage - 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 92a3f91..2d332dc 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -51,7 +51,7 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/PowerAdvantage - 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 079ab5b..a338327 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -8,8 +8,8 @@ Steam Advantage 2.2.8.116051 (local port candidate) - Preserve registry identities, recipe and trade quantities, machine ratios and NBT. - Retain exact track/platform opacity, collision and redstone behavior. - Add exact native level, persistence and callback regressions. -- Pin the Power Advantage build that preserves legacy Forge swimming-speed values and modifiers during upgrades. -- Pass all 87 Java tests with Gradle and the Eclipse compiler, along with release and Eclipse audits. +- Pin the Power Advantage build that preserves legacy Forge swimming speed, nametag distance, gravity and reach values and modifiers during upgrades. +- Pass all 87 Java tests with Gradle and the Eclipse compiler, along with release and Eclipse audits; repeat runtime qualification for this dependency pin. - Recheck connected-machine upgrades, recipes, mining and full-restart operation through the shared Advantage Works rig; keep wider migration checks and manual acceptance separate. Steam Advantage 2.2.7.115021 diff --git a/README.md b/README.md index b46cefb..88a308f 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ **Minecraft 1.16.5 port candidate, version 2.2.8.116051.** This branch is a local candidate pending manual acceptance and publication approval. All 87 Java tests pass with Gradle and the Eclipse compiler, along with release -and Eclipse audits. Combined machine, recipe, mining and connected-world upgrade -checks pass against the pinned jars; wider migration checks are still being -completed. Accepted 1.15 results do not qualify this candidate. +and Eclipse audits against the updated Power dependency. +Bounded runtime checks will follow after the candidate inputs are sealed. +Earlier-candidate results and accepted 1.15 results do not qualify this candidate. 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 @@ -22,14 +22,18 @@ Compilation and Minecraft launches use Temurin 8.0.502+7 and Java 8 bytecode; Mavenizer uses Temurin 25.0.3+9.0.LTS. Power Advantage 2.4.7.116051 remains a separate required mod. The current local -candidate uses source `3f1100e6f75b1fb949cc883be7288aa30789876d`. +candidate uses source `bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7`. Its development jar SHA-256 is -`1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4`. +`2FB923944A456B4F26AB2F9212C646469CE3F49BFD4DAE894C15559B48908386`. These exact pins are recorded in `gradle.properties` and audited during builds. Use an immutable development jar through `-PpowerAdvantageDeobfJar=`. Release audits reject missing, placeholder, or mismatched pins. These source pins are local candidates, not publication approval. +Power's migration hook preserves legacy Forge swimming speed, nametag distance, +gravity and reach attributes, including their values and modifiers. Steam uses +that shared hook without duplicating the conversion. + Earlier dependency-candidate build and runtime receipts remain historical evidence for their original inputs. They do not qualify the current candidate. Automated build and test results, bounded runtime checks, and manual acceptance are separate diff --git a/build.gradle b/build.gradle index ffa0d04..b05ca6b 100644 --- a/build.gradle +++ b/build.gradle @@ -378,8 +378,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') } String mainSource = file( diff --git a/gradle.properties b/gradle.properties index 782c292..379caca 100644 --- a/gradle.properties +++ b/gradle.properties @@ -37,9 +37,9 @@ cf_versions=1.16.5 poweradvantage_version=2.4.7.116051 poweradvantage_source_repository=MinecraftModDevelopmentMods/PowerAdvantage -# Power E local candidate; automated verification and manual acceptance are separate. -poweradvantage_source_ref=3f1100e6f75b1fb949cc883be7288aa30789876d -poweradvantage_deobf_sha256=1A3E5B9EE45CF932CE963146D016E5270BD587A5D5AA2B9283886FF89EF14FD4 +# Power F local candidate; automated verification and manual acceptance are separate. +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/steamadvantage/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java index 2e66e59..0046834 100644 --- a/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java @@ -8,13 +8,24 @@ public class BuildWorkflowContractTest { @Test public void everyHostedBuildUsesPinnedToolchainProjectProperties() throws Exception { + String powerSource = "bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7"; + String powerHash = "2FB923944A456B4F26AB2F9212C646469CE3F49BFD4DAE894C15559B48908386"; + String properties = new String(Files.readAllBytes(Paths.get("gradle.properties")), + StandardCharsets.UTF_8); + assertTrue(properties.contains("poweradvantage_source_ref=" + powerSource)); + assertTrue(properties.contains("poweradvantage_deobf_sha256=" + powerHash)); + for (String name : new String[] {"build.gradle", "README.md"}) { + String source = new String(Files.readAllBytes(Paths.get(name)), StandardCharsets.UTF_8); + assertTrue(name, source.contains(powerSource)); + assertTrue(name, source.contains(powerHash)); + } for (String name : new String[] {"ci.yml", "codeql-analysis.yml"}) { String source = new String(Files.readAllBytes(Paths.get(".github/workflows", name)), StandardCharsets.UTF_8); assertTrue(name, source.contains("ref: 995f6cc4dd2d5eecc628a42e5c43fa5390c24bca")); assertTrue(name, source.contains("BaseMetals-3.1.1.116051-deobf.jar")); assertTrue(name, source.contains("ref: a113e5d767169189f0e35ade1e173a12d550b00e")); - assertTrue(name, source.contains("ref: 3f1100e6f75b1fb949cc883be7288aa30789876d")); + assertTrue(name, source.contains("ref: " + powerSource)); assertTrue(name, source.contains("Final Power 1.16 dependency pin is pending.")); assertTrue(name, source.contains("^[a-f0-9]{40}$")); assertTrue(name, source.contains("^[A-F0-9]{64}$")); From 570b6d01f6fe5c254082b238829bd7ed050bdacb Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Tue, 27 Oct 2026 21:46:33 +0000 Subject: [PATCH 7/9] Record Steam Advantage's 1.16.5 shared runtime checks --- CHANGELOG.txt | 2 +- README.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index a338327..4a6660c 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -9,7 +9,7 @@ Steam Advantage 2.2.8.116051 (local port candidate) - Retain exact track/platform opacity, collision and redstone behavior. - Add exact native level, persistence and callback regressions. - Pin the Power Advantage build that preserves legacy Forge swimming speed, nametag distance, gravity and reach values and modifiers during upgrades. -- Pass all 87 Java tests with Gradle and the Eclipse compiler, along with release and Eclipse audits; repeat runtime qualification for this dependency pin. +- Pass all 87 Java tests with Gradle and the Eclipse compiler, along with release and Eclipse audits against the pinned Power dependency. - Recheck connected-machine upgrades, recipes, mining and full-restart operation through the shared Advantage Works rig; keep wider migration checks and manual acceptance separate. Steam Advantage 2.2.7.115021 diff --git a/README.md b/README.md index 88a308f..ba97c5c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ This branch is a local candidate pending manual acceptance and publication approval. All 87 Java tests pass with Gradle and the Eclipse compiler, along with release and Eclipse audits against the updated Power dependency. -Bounded runtime checks will follow after the candidate inputs are sealed. +Packaged machine, migration, recipe, mining and restart checks use this same +candidate. Their exact scope and remaining limits are in the shared record below. Earlier-candidate results and accepted 1.15 results do not qualify this candidate. The [shared test record](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.16.5/docs/1.16/CURRENT-QUALIFICATION.md) From bc24db71fd6bf8f04ff0c8b538dbe0f8705e425a Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Fri, 30 Oct 2026 20:56:21 +0000 Subject: [PATCH 8/9] Fix Steam Advantage machine state and strengthen Minecraft 1.16.5 tests --- CHANGELOG.txt | 13 +- README.md | 15 +- .../mc/steamadvantage/gui/GUIHelper.java | 8 + .../mc/steamadvantage/items/MusketItem.java | 53 ++--- .../machines/BlastFurnaceTileEntity.java | 12 + .../machines/CoalBoilerTileEntity.java | 16 +- .../machines/ElectricBoilerTileEntity.java | 16 +- .../machines/GeothermalBoilerTileEntity.java | 16 +- .../machines/RockCrusherTileEntity.java | 12 + .../machines/SteamPumpTileEntity.java | 27 ++- .../machines/SteamStillTileEntity.java | 31 ++- .../mc/steamadvantage/util/SoundHelper.java | 26 ++- .../mc/steamadvantage/gui/GUIHelperTest.java | 20 ++ .../items/MusketTargetingContractTest.java | 80 +++++++ .../CoalBoilerFillPersistenceTest.java | 219 ++++++++++++++++++ .../machines/RockCrusherComparatorTest.java | 25 ++ .../RockCrusherReloadRedstoneTest.java | 92 ++++++++ .../SteamOperationalPumpSourceTest.java | 150 ++++++++++++ .../SteamOperationalStillCapacityTest.java | 91 ++++++++ .../WaterBoilerFluidBoundaryTest.java | 166 +++++++++++++ .../WaterBoilerTankNotificationTest.java | 165 +++++++++++++ .../util/SoundHelperLoadedPlayersTest.java | 128 ++++++++++ 22 files changed, 1315 insertions(+), 66 deletions(-) create mode 100644 src/test/java/zone/moddev/mc/steamadvantage/gui/GUIHelperTest.java create mode 100644 src/test/java/zone/moddev/mc/steamadvantage/items/MusketTargetingContractTest.java create mode 100644 src/test/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerFillPersistenceTest.java create mode 100644 src/test/java/zone/moddev/mc/steamadvantage/machines/RockCrusherComparatorTest.java create mode 100644 src/test/java/zone/moddev/mc/steamadvantage/machines/RockCrusherReloadRedstoneTest.java create mode 100644 src/test/java/zone/moddev/mc/steamadvantage/machines/SteamOperationalPumpSourceTest.java create mode 100644 src/test/java/zone/moddev/mc/steamadvantage/machines/SteamOperationalStillCapacityTest.java create mode 100644 src/test/java/zone/moddev/mc/steamadvantage/machines/WaterBoilerFluidBoundaryTest.java create mode 100644 src/test/java/zone/moddev/mc/steamadvantage/machines/WaterBoilerTankNotificationTest.java create mode 100644 src/test/java/zone/moddev/mc/steamadvantage/util/SoundHelperLoadedPlayersTest.java diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 4a6660c..c22fde9 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,16 @@ Steam Advantage 2.2.8.116051 (local port candidate) +- Read live redstone before the crusher and furnace resume after loading, preserving saved work and the first-tick steam heat bonus without changing the normal polling interval. +- Save real coal-boiler tank changes immediately, leave simulations unchanged, and return an empty result for null, empty or mismatched drain requests. +- Honour the water-only input of coal, electric and geothermal boilers even when empty, and safely refuse null, empty or mismatched fluid requests. +- Save accepted external tank changes in electric and geothermal boilers immediately, with the same simulation and client-side safeguards as the coal boiler. +- Keep pressure needles, fluid levels, flames and progress arrows inside their GUI frames, including invalid or oversized readings. +- Preserve pump fluid when a full receiver rejects it, and stop distillation before output would overflow. +- Consume actual liquid source blocks before crediting pumped fluid; native block removal otherwise preserves the source. +- Use native bucket pickup to retain waterlogged hosts; leave unsupported source blocks untouched without an air fallback. +- Allow a loaded musket to fire after its last cartridge was consumed during reload. +- Send nearby sounds only to loaded server players, preserving 16/50-block bounding-box ranges without scanning chunks. +- Pick musket targets from loaded server entities and stop shots at nearer terrain instead of damaging entities through walls. - Target Minecraft 1.16.5 / Forge 36.2.34 with official 1.16.5 mappings. - Keep Java 8 compilation and runtime with ForgeGradle 7.0.34 / Gradle 9.6.1. - Use world-only conduit callbacks and Power Advantage's native tile lifecycle. @@ -9,7 +20,7 @@ Steam Advantage 2.2.8.116051 (local port candidate) - Retain exact track/platform opacity, collision and redstone behavior. - Add exact native level, persistence and callback regressions. - Pin the Power Advantage build that preserves legacy Forge swimming speed, nametag distance, gravity and reach values and modifiers during upgrades. -- Pass all 87 Java tests with Gradle and the Eclipse compiler, along with release and Eclipse audits against the pinned Power dependency. +- Check the current Java tests with both Gradle and the Eclipse compiler, alongside release and Eclipse audits against the pinned Power dependency. - Recheck connected-machine upgrades, recipes, mining and full-restart operation through the shared Advantage Works rig; keep wider migration checks and manual acceptance separate. Steam Advantage 2.2.7.115021 diff --git a/README.md b/README.md index ba97c5c..956fc6f 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,12 @@ **Minecraft 1.16.5 port candidate, version 2.2.8.116051.** This branch is a local candidate pending manual acceptance and publication approval. -All 87 Java tests pass with Gradle and the Eclipse compiler, along with release -and Eclipse audits against the updated Power dependency. -Packaged machine, migration, recipe, mining and restart checks use this same -candidate. Their exact scope and remaining limits are in the shared record below. +The follow-up checks use finite supplies and ordinary server ticks to measure +actual machine output, energy use, blocked routes and saved state. They also +cover fluid pickup without destroying waterlogged blocks. Rendered GUI checks +require machine names and inventory 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. Earlier-candidate results and accepted 1.15 results do not qualify this candidate. The [shared test record](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.16.5/docs/1.16/CURRENT-QUALIFICATION.md) @@ -97,3 +99,8 @@ migration hook. Upgrade testing must use disposable whole-world copies with pinned inputs. Preserve original worlds and backups; never open a world in an older Minecraft version after upgrading it. Manual acceptance and publication approval remain separate from automated evidence. + +The shared [machine operating checks](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.16.5/docs/1.16/OPERATING-TESTS.md) +exercise finite boiler, processing, pumping, storage, elevator and musket jobs. +They check real output and resource use, including failed jobs and complete +server restarts. Live player controls and rendering still need a walkthrough. diff --git a/src/main/java/zone/moddev/mc/steamadvantage/gui/GUIHelper.java b/src/main/java/zone/moddev/mc/steamadvantage/gui/GUIHelper.java index faebeec..a1085ee 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/gui/GUIHelper.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/gui/GUIHelper.java @@ -25,6 +25,7 @@ public static float maxDelta(float newValue,float oldValue,float maxChange){ public static void drawNeedle(float pivotX, float pivotY, float zLevel, float value) { + value = displayLevel(value); final float pixelSize = 1.0f / 256; // conversion factor @@ -85,6 +86,7 @@ public static void drawNeedle(float pivotX, float pivotY, float zLevel, } public static void drawFlameProgress(int x, int y, float flameHeight, GUIContainer gc){ + flameHeight = displayLevel(flameHeight); if(flameHeight <= 0) return; final int flameTexX = 200; final int flameTexY = 0; @@ -100,6 +102,7 @@ public static void drawFlameProgress(int x, int y, float flameHeight, GUIContain public static void drawFluidBar(FluidStack fs, float barHeight, int xPos, int yPos, GUIContainer guiContainer, int x, int y, float z, ResourceLocation displayImage, int texOverlayX, int texOverlayY, int texOverlayW, int texOverlayH){ + barHeight = displayLevel(barHeight); final int texMarginW = (texOverlayW - 16) / 2; final int texMarginH = (texOverlayH - 60) / 2; final int w = 16; @@ -117,6 +120,7 @@ public static void drawFluidBar(FluidStack fs, float barHeight, int xPos, int yP public static void drawDownArrowProgress(int x, int y, float progress, GUIContainer gc) { + progress = displayLevel(progress); if(progress <= 0) return; final int arrowTexX = 184; final int arrowTexY = 0; @@ -128,4 +132,8 @@ public static void drawDownArrowProgress(int x, int y, float progress, gc.blit(x, y, arrowTexX, arrowTexY, width, h); } } + + static float displayLevel(float value) { + return Float.isFinite(value) ? Math.max(0F, Math.min(1F, value)) : 0F; + } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/items/MusketItem.java b/src/main/java/zone/moddev/mc/steamadvantage/items/MusketItem.java index dd8bd11..0f802fd 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/items/MusketItem.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/items/MusketItem.java @@ -4,6 +4,7 @@ import static zone.moddev.mc.steamadvantage.util.SoundHelper.playSoundAtPosition; import java.util.List; +import java.util.Optional; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; @@ -97,7 +98,7 @@ public UseAction getUseAnimation(ItemStack stack){ public ActionResult use(World world, PlayerEntity playerEntity, Hand hand){ ItemStack srcItemStack = playerEntity.getItemInHand(hand); if(hand != Hand.MAIN_HAND) return ActionResult.pass(srcItemStack); - if(!hasAmmo(playerEntity, srcItemStack)) return ActionResult.fail(srcItemStack); + if(isNotLoaded(srcItemStack) && !hasAmmo(playerEntity, srcItemStack)) return ActionResult.fail(srcItemStack); if(isNotLoaded(srcItemStack) && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.rapid_reload, srcItemStack) > 0){ // instant reload decrementAmmo(playerEntity,srcItemStack); @@ -350,38 +351,35 @@ public static void decrementAmmo(LivingEntity e, ItemStack musket) { public static RayTraceResult rayTraceBlocksAndEntities(World w, double maxRange, LivingEntity source){ - double rangeSqr = maxRange * maxRange; Vector3d rayOrigin = new Vector3d(source.getX(), source.getY() + source.getEyeHeight(), source.getZ()); Vector3d rayDirection = source.getLookAngle(); - BlockPos srcPos = source.blockPosition(); - AxisAlignedBB aoi = new AxisAlignedBB(srcPos.getX() - maxRange, srcPos.getY() - maxRange, srcPos.getZ() - maxRange, - srcPos.getX() + maxRange, srcPos.getY() + maxRange, srcPos.getZ() + maxRange); - List entities = w.getEntities(source, aoi); - double closestDistSqr = Double.MAX_VALUE; + BlockRayTraceResult terrainHit = w.clip(new RayTraceContext(rayOrigin, rayOrigin.add(rayDirection.scale(maxRange)), + RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.SOURCE_ONLY, source)); + Vector3d rayEnd = terrainHit.getLocation(); + AxisAlignedBB aoi = new AxisAlignedBB(rayOrigin, rayEnd).inflate(1.0D); + // Server spatial entity queries can synchronously generate chunks around the shooter. + Iterable entities = w instanceof ServerWorld ? ((ServerWorld)w).getAllEntities() : w.getEntities(source, aoi); + double closestDistSqr = rayOrigin.distanceToSqr(rayEnd); Entity closestEntity = null; + Vector3d closestHit = null; for(Entity e : entities){ - double distSqr = e.distanceToSqr(source.getX(), source.getY(), source.getZ()); - if(distSqr < rangeSqr){ - // e is within range - AxisAlignedBB box = e.getBoundingBox(); - if(rayIntersectsBoundingBox(rayOrigin,rayDirection, box)){ - // e is in cross-hairs - if(distSqr < closestDistSqr){ - // e is closest entity in line of fire - closestDistSqr = distSqr; - closestEntity = e; - } + if(e == source || e.removed || e.isSpectator() || !aoi.intersects(e.getBoundingBox())) continue; + Optional hit = rayHitBeforeTerrain(rayOrigin, rayEnd, e.getBoundingBox()); + if(hit.isPresent()){ + double distSqr = rayOrigin.distanceToSqr(hit.get()); + if(distSqr < closestDistSqr){ + closestDistSqr = distSqr; + closestEntity = e; + closestHit = hit.get(); } } } - if(closestEntity == null) { - return w.clip(new RayTraceContext(rayOrigin, rayOrigin.add(mul(rayDirection, maxRange)), - RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.SOURCE_ONLY, source)); - } else { - Vector3d pos = new Vector3d(closestEntity.getX(), closestEntity.getY()+closestEntity.getEyeHeight(), closestEntity.getZ()); - RayTraceResult entityCollision = new EntityRayTraceResult(closestEntity, pos); - return entityCollision; - } + return closestEntity == null ? terrainHit : new EntityRayTraceResult(closestEntity, closestHit); + } + + static Optional rayHitBeforeTerrain(Vector3d origin, Vector3d terrainEnd, AxisAlignedBB target){ + Optional hit = target.contains(origin) ? Optional.of(origin) : target.clip(origin, terrainEnd); + return hit.filter(point -> origin.distanceToSqr(point) < origin.distanceToSqr(terrainEnd)); } public static boolean rayIntersectsBoundingBox(Vector3d rayOrigin, Vector3d rayDirection, AxisAlignedBB box){ @@ -414,9 +412,6 @@ public static boolean rayIntersectsBoundingBox(Vector3d rayOrigin, Vector3d rayD } - 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); } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/BlastFurnaceTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/BlastFurnaceTileEntity.java index 47f1c61..198fca5 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/BlastFurnaceTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/BlastFurnaceTileEntity.java @@ -38,6 +38,13 @@ public class BlastFurnaceTileEntity extends cyano.poweradvantage.api.simple.Tile private static final float minSmeltingTemperature = 100f; private boolean redstone = true; + private boolean redstoneInitialized = false; + + @Override + public void onLoad() { + super.onLoad(); + redstoneInitialized = false; + } public BlastFurnaceTileEntity() { super(zone.moddev.mc.steamadvantage.init.Entities.STEAM_FURNACE, Power.steam_power, 200, "tile.steamadvantage.steam_furnace.name"); @@ -66,6 +73,10 @@ public float getTemperatureLevel(){ @Override public void tickUpdate(boolean isServerWorld) { if(isServerWorld){ + if (!redstoneInitialized && getLevel() != null) { + redstone = hasRedstoneSignal(); + redstoneInitialized = true; + } // fual input heat float e = 0; if(burnTime > 0){ @@ -172,6 +183,7 @@ public void powerUpdate(){ this.sync(); } redstone = hasRedstoneSignal(); + redstoneInitialized = true; } private boolean hasRedstoneSignal() { diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerTileEntity.java index 6de623e..da142c8 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerTileEntity.java @@ -39,7 +39,15 @@ public class CoalBoilerTileEntity extends cyano.poweradvantage.api.simple.TileEn public CoalBoilerTileEntity() { super(zone.moddev.mc.steamadvantage.init.Entities.STEAM_BOILER_COAL, new ConduitType[]{Power.steam_power,Fluids.fluidConduit_general}, new float[]{1000,1000}, "tile.steamadvantage.steam_boiler_coal.name"); - tank = new FluidTank(FluidTank.BUCKET_VOLUME * 4); + tank = new FluidTank(FluidTank.BUCKET_VOLUME * 4) { + @Override + protected void onContentsChanged() { + if (CoalBoilerTileEntity.this.getLevel() != null + && !CoalBoilerTileEntity.this.getLevel().isClientSide) { + CoalBoilerTileEntity.this.setChanged(); + } + } + }; inventory = new ItemStack[1]; } @@ -349,6 +357,8 @@ && getTank().getFluidAmount() > 0 */ @Override public int fill(Direction face, FluidStack fluid, boolean forReal) { + if (fluid == null || fluid.amount <= 0 || !canFill(face, fluid.getFluid()) + || getTank().getFluidAmount() >= getTank().getCapacity()) return 0; if(getTank().getFluidAmount() <= 0 || getTank().getFluid().getFluid().equals(fluid.getFluid())){ return getTank().fill(fluid, forReal); } else { @@ -363,10 +373,11 @@ public int fill(Direction face, FluidStack fluid, boolean forReal) { */ @Override public FluidStack drain(Direction face, FluidStack fluid, boolean forReal) { + if (fluid == null || fluid.amount <= 0) return null; if(getTank().getFluidAmount() > 0 && getTank().getFluid().getFluid().equals(fluid.getFluid())){ return getTank().drain(fluid.amount,forReal); } else { - return new FluidStack(getTank().getFluid().getFluid(),0); + return null; } } /** @@ -377,6 +388,7 @@ public FluidStack drain(Direction face, FluidStack fluid, boolean forReal) { */ @Override public FluidStack drain(Direction face, int amount, boolean forReal) { + if (amount <= 0) return null; if(getTank().getFluidAmount() > 0 ){ return getTank().drain(amount,forReal); } else { diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/ElectricBoilerTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/ElectricBoilerTileEntity.java index 5aaa51c..43a2648 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/ElectricBoilerTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/ElectricBoilerTileEntity.java @@ -40,7 +40,15 @@ public ElectricBoilerTileEntity() { super(zone.moddev.mc.steamadvantage.init.Entities.STEAM_BOILER_ELECTRIC, new ConduitType[]{Power.steam_power, ELECTRIC_POWER, Fluids.fluidConduit_general}, new float[]{100, MAX_ELECTRICITY, 1000}, "tile.steamadvantage.steam_boiler_electric.name"); - tank = new FluidTank(FluidTank.BUCKET_VOLUME * 2); + tank = new FluidTank(FluidTank.BUCKET_VOLUME * 2) { + @Override + protected void onContentsChanged() { + if (ElectricBoilerTileEntity.this.getLevel() != null + && !ElectricBoilerTileEntity.this.getLevel().isClientSide) { + ElectricBoilerTileEntity.this.setChanged(); + } + } + }; inventory = new ItemStack[0]; } @@ -301,6 +309,8 @@ public PowerRequest getPowerRequest(ConduitType offer) { */ @Override public int fill(Direction face, FluidStack fluid, boolean forReal) { + if (fluid == null || fluid.amount <= 0 || !canFill(face, fluid.getFluid()) + || getTank().getFluidAmount() >= getTank().getCapacity()) return 0; if(getTank().getFluidAmount() <= 0 || getTank().getFluid().getFluid().equals(fluid.getFluid())){ return getTank().fill(fluid, forReal); } else { @@ -315,10 +325,11 @@ public int fill(Direction face, FluidStack fluid, boolean forReal) { */ @Override public FluidStack drain(Direction face, FluidStack fluid, boolean forReal) { + if (fluid == null || fluid.amount <= 0) return null; if(getTank().getFluidAmount() > 0 && getTank().getFluid().getFluid().equals(fluid.getFluid())){ return getTank().drain(fluid.amount,forReal); } else { - return new FluidStack(getTank().getFluid().getFluid(),0); + return null; } } /** @@ -329,6 +340,7 @@ public FluidStack drain(Direction face, FluidStack fluid, boolean forReal) { */ @Override public FluidStack drain(Direction face, int amount, boolean forReal) { + if (amount <= 0) return null; if(getTank().getFluidAmount() > 0 ){ return getTank().drain(amount,forReal); } else { diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/GeothermalBoilerTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/GeothermalBoilerTileEntity.java index 8484e3f..f08af3d 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/GeothermalBoilerTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/GeothermalBoilerTileEntity.java @@ -43,7 +43,15 @@ public class GeothermalBoilerTileEntity extends cyano.poweradvantage.api.simple. public GeothermalBoilerTileEntity() { super(zone.moddev.mc.steamadvantage.init.Entities.STEAM_BOILER_GEOTHERMAL, new ConduitType[]{Power.steam_power,Fluids.fluidConduit_general}, new float[]{100,1000}, "tile.steamadvantage.steam_boiler_geothermal.name"); - tank = new FluidTank(FluidTank.BUCKET_VOLUME * 2); + tank = new FluidTank(FluidTank.BUCKET_VOLUME * 2) { + @Override + protected void onContentsChanged() { + if (GeothermalBoilerTileEntity.this.getLevel() != null + && !GeothermalBoilerTileEntity.this.getLevel().isClientSide) { + GeothermalBoilerTileEntity.this.setChanged(); + } + } + }; inventory = new ItemStack[0]; } @@ -337,6 +345,8 @@ public PowerRequest getPowerRequest(ConduitType offer) { */ @Override public int fill(Direction face, FluidStack fluid, boolean forReal) { + if (fluid == null || fluid.amount <= 0 || !canFill(face, fluid.getFluid()) + || getTank().getFluidAmount() >= getTank().getCapacity()) return 0; if(getTank().getFluidAmount() <= 0 || getTank().getFluid().getFluid().equals(fluid.getFluid())){ return getTank().fill(fluid, forReal); } else { @@ -351,10 +361,11 @@ public int fill(Direction face, FluidStack fluid, boolean forReal) { */ @Override public FluidStack drain(Direction face, FluidStack fluid, boolean forReal) { + if (fluid == null || fluid.amount <= 0) return null; if(getTank().getFluidAmount() > 0 && getTank().getFluid().getFluid().equals(fluid.getFluid())){ return getTank().drain(fluid.amount,forReal); } else { - return new FluidStack(getTank().getFluid().getFluid(),0); + return null; } } /** @@ -365,6 +376,7 @@ public FluidStack drain(Direction face, FluidStack fluid, boolean forReal) { */ @Override public FluidStack drain(Direction face, int amount, boolean forReal) { + if (amount <= 0) return null; if(getTank().getFluidAmount() > 0 ){ return getTank().drain(amount,forReal); } else { diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/RockCrusherTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/RockCrusherTileEntity.java index fb9e7a8..9c894a8 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/RockCrusherTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/RockCrusherTileEntity.java @@ -33,6 +33,13 @@ public RockCrusherTileEntity() { } private boolean redstone = true; + private boolean redstoneInitialized = false; + + @Override + public void onLoad() { + super.onLoad(); + redstoneInitialized = false; + } private int timeSinceLastSteamBurst = 0; @@ -41,6 +48,10 @@ public RockCrusherTileEntity() { @Override public void tickUpdate(boolean isServerWorld) { if(isServerWorld){ + if (!redstoneInitialized && getLevel() != null) { + redstone = hasRedstoneSignal(); + redstoneInitialized = true; + } // reset progress when item in slot changes ItemStack input = inventory[0]; if(itemCheck != null && (input == null || input.isEmpty() || ItemStack.isSame(itemCheck, input) == false)){ @@ -113,6 +124,7 @@ public void powerUpdate(){ super.powerUpdate(); redstone = hasRedstoneSignal(); + redstoneInitialized = true; if(oldSteam != this.getEnergy(Power.steam_power) || progress != oldProgress){ this.sync(); diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamPumpTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamPumpTileEntity.java index e8d0ab8..dc61101 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamPumpTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamPumpTileEntity.java @@ -11,8 +11,8 @@ import zone.moddev.mc.poweradvantage.util.FluidHandlerHelper; import zone.moddev.mc.steamadvantage.init.Power; import net.minecraft.block.BlockState; +import net.minecraft.block.IBucketPickupHandler; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.block.Blocks; import net.minecraft.util.SoundEvents; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; @@ -21,6 +21,7 @@ import net.minecraft.util.SoundCategory; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraft.world.IWorld; import net.minecraft.fluid.Fluid; import cyano.poweradvantage.api.fluid.FluidStack; import cyano.poweradvantage.api.fluid.FluidTank; @@ -89,11 +90,14 @@ public void tickUpdate(boolean isServerWorld) { // Found a fluid to suck-up! BlockState blockstate = w.getBlockState(fluidSource); Fluid f = getFluid(blockstate); - if(f != null && getEnergy(Power.steam_power) >= cost){ - this.getTank().fill(new FluidStack(f,FluidTank.BUCKET_VOLUME), true); - this.subtractEnergy(cost, Power.steam_power); - w.removeBlock(fluidSource, false); - success = true; + if(f != null && getEnergy(Power.steam_power) >= cost + && getTank().fill(new FluidStack(f,FluidTank.BUCKET_VOLUME), false) == FluidTank.BUCKET_VOLUME){ + Fluid collected = pickupSource(w, fluidSource, blockstate); + if(collected != net.minecraft.fluid.Fluids.EMPTY){ + this.getTank().fill(new FluidStack(collected,FluidTank.BUCKET_VOLUME), true); + this.subtractEnergy(cost, Power.steam_power); + success = true; + } } } timeUntilNextPump = PUMP_INTERVAL; @@ -120,6 +124,15 @@ private Fluid getFluid(BlockState blockstate) { return blockstate.getFluidState().isEmpty() ? null : blockstate.getFluidState().getType(); } + static Fluid pickupSource(IWorld world, BlockPos pos, BlockState state) { + if(!state.getFluidState().isSource() || !(state.getBlock() instanceof IBucketPickupHandler)){ + return net.minecraft.fluid.Fluids.EMPTY; + } + // Native pickup preserves waterlogged hosts; unsupported blocks have no destructive fallback. + Fluid collected = ((IBucketPickupHandler)state.getBlock()).takeLiquid(world, pos, state); + return collected == null ? net.minecraft.fluid.Fluids.EMPTY : collected; + } + private BlockPos scan(Set searchSpace, BlockPos coord, int limit) { @@ -197,7 +210,7 @@ public void powerUpdate(){ IAdvantageFluidHandler handler = FluidHandlerHelper.getHandler(neighbor, dir.getOpposite()); if(handler != null){ int d = handler.fill(dir.getOpposite(), fluid, true); - getTank().drain(Math.max(d,1),true); // no free energy! + if(d > 0) getTank().drain(d,true); fluid = getTank().getFluid(); } } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamStillTileEntity.java b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamStillTileEntity.java index 31d8520..c06041e 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamStillTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamStillTileEntity.java @@ -53,8 +53,7 @@ public void tickUpdate(boolean isServerWorld) { if(!redstone){ if(getInputTank().getFluidAmount() > 0 && getEnergy(Power.steam_power) > steamPerDistill - && canDistill(getInputTank().getFluid())){ - distill(); + && canDistill(getInputTank().getFluid()) && distill()){ this.subtractEnergy(steamPerDistill, Power.steam_power); if(timeSinceSound > 200){ playSoundAtTileEntity(SoundEvents.LAVA_AMBIENT, SoundCategory.AMBIENT, 0.3f, 1.5f, this); @@ -294,20 +293,34 @@ private boolean canDistill(Fluid f) { } private boolean canDistill(FluidStack fs) { + if(fs == null) return false; DistillationRecipe recipe = DistillationRecipeRegistry.getInstance().getDistillationRecipeForFluid(fs.getFluid()); if(recipe == null) return false; - if(this.getOutputTank().getFluidAmount() > 0){ - return recipe.isValidInput(fs) && recipe.isValidOutput(getOutputTank().getFluid()); - } else { - return recipe.isValidInput(fs); + return recipe.isValidInput(fs) && (outputTank.getFluidAmount() == 0 + || recipe.isValidOutput(outputTank.getFluid())); + } + + private int distillationApplications(DistillationRecipe recipe, FluidStack input) { + if(!recipe.isValidInput(input)) return 0; + if(outputTank.getFluidAmount() > 0 && !recipe.isValidOutput(outputTank.getFluid())) return 0; + // Preview on a copy: a blocked or partially full output must not destroy input. + for(int applications = speed; applications > 0; applications--){ + FluidStack output = recipe.applyRecipe(input.copy(), applications); + if(output != null && outputTank.fill(output, false) == output.amount) return applications; } + return 0; } - private void distill(){ + private boolean distill(){ DistillationRecipe recipe = DistillationRecipeRegistry.getInstance() .getDistillationRecipeForFluid(getInputTank().getFluid().getFluid()); - FluidStack output = recipe.applyRecipe(inputTank.getFluid(), speed); - getOutputTank().fill(output, true); + int applications = distillationApplications(recipe, inputTank.getFluid()); + if(applications > 0){ + FluidStack output = recipe.applyRecipe(inputTank.getFluid(), applications); + getOutputTank().fill(output, true); + return true; + } + return false; } diff --git a/src/main/java/zone/moddev/mc/steamadvantage/util/SoundHelper.java b/src/main/java/zone/moddev/mc/steamadvantage/util/SoundHelper.java index 169fbf4..8cccc05 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/util/SoundHelper.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/util/SoundHelper.java @@ -1,8 +1,10 @@ package zone.moddev.mc.steamadvantage.util; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.network.play.server.SPlaySoundPacket; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EntityPredicates; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.AxisAlignedBB; @@ -10,8 +12,6 @@ import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; -import java.util.List; - public class SoundHelper { public static void playSoundAtTileEntity(SoundEvent sound, SoundCategory soundType, float volume, float pitch, TileEntity te){ @@ -23,11 +23,14 @@ public static void playSoundAtTileEntity(SoundEvent sound, SoundCategory soundTy public static void playSoundAtPosition(double x, double y, double z, SoundEvent sound, SoundCategory soundType, float volume, float pitch, World serverWorld){ if(serverWorld.isClientSide) return; final double range = 16; - List players = serverWorld.getEntitiesOfClass(ServerPlayerEntity.class, new AxisAlignedBB( + final AxisAlignedBB area = new AxisAlignedBB( x - range, y - range, z - range, - x + range, y + range, z + range)); - for(ServerPlayerEntity player : players){ - player.connection.send(new SPlaySoundPacket(sound.getRegistryName(), soundType, + x + range, y + range, z + range); + for(PlayerEntity candidate : serverWorld.players()){ + if(!(candidate instanceof ServerPlayerEntity) || !EntityPredicates.NO_SPECTATORS.test(candidate) + || !area.intersects(candidate.getBoundingBox())) continue; + ServerPlayerEntity player = (ServerPlayerEntity) candidate; + if(player.connection != null) player.connection.send(new SPlaySoundPacket(sound.getRegistryName(), soundType, new Vector3d(x, y, z), volume, pitch)); } } @@ -35,11 +38,14 @@ public static void playSoundAtPosition(double x, double y, double z, SoundEvent public static void playBigSoundAtPosition(double x, double y, double z, SoundEvent sound, SoundCategory soundType, float volume, float pitch, World serverWorld){ if(serverWorld.isClientSide) return; final double range = 50; - List players = serverWorld.getEntitiesOfClass(ServerPlayerEntity.class, new AxisAlignedBB( + final AxisAlignedBB area = new AxisAlignedBB( x - range, y - range, z - range, - x + range, y + range, z + range)); - for(ServerPlayerEntity player : players){ - player.connection.send(new SPlaySoundPacket(sound.getRegistryName(), soundType, + x + range, y + range, z + range); + for(PlayerEntity candidate : serverWorld.players()){ + if(!(candidate instanceof ServerPlayerEntity) || !EntityPredicates.NO_SPECTATORS.test(candidate) + || !area.intersects(candidate.getBoundingBox())) continue; + ServerPlayerEntity player = (ServerPlayerEntity) candidate; + if(player.connection != null) player.connection.send(new SPlaySoundPacket(sound.getRegistryName(), soundType, new Vector3d(x, y, z), volume, pitch)); } } diff --git a/src/test/java/zone/moddev/mc/steamadvantage/gui/GUIHelperTest.java b/src/test/java/zone/moddev/mc/steamadvantage/gui/GUIHelperTest.java new file mode 100644 index 0000000..07316fd --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/gui/GUIHelperTest.java @@ -0,0 +1,20 @@ +package zone.moddev.mc.steamadvantage.gui; + +import org.junit.Test; +import static org.junit.Assert.*; + +public class GUIHelperTest { + @Test public void readingsKeepTheirScaleButStayInsideTheGauge() { + assertEquals(0F, GUIHelper.displayLevel(-1F), 0F); + assertEquals(0F, GUIHelper.displayLevel(0F), 0F); + assertEquals(0.5F, GUIHelper.displayLevel(0.5F), 0F); + assertEquals(1F, GUIHelper.displayLevel(1F), 0F); + assertEquals(1F, GUIHelper.displayLevel(15F), 0F); + } + + @Test public void nonfiniteReadingsAreSafeToDraw() { + for (float value : new float[]{Float.NaN, Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY}) { + assertEquals(0F, GUIHelper.displayLevel(value), 0F); + } + } +} diff --git a/src/test/java/zone/moddev/mc/steamadvantage/items/MusketTargetingContractTest.java b/src/test/java/zone/moddev/mc/steamadvantage/items/MusketTargetingContractTest.java new file mode 100644 index 0000000..7bec481 --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/items/MusketTargetingContractTest.java @@ -0,0 +1,80 @@ +package zone.moddev.mc.steamadvantage.items; + +import java.io.InputStream; +import java.util.Optional; +import net.minecraft.util.Direction; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.vector.Vector3d; +import org.junit.BeforeClass; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import static org.junit.Assert.*; + +public class MusketTargetingContractTest { + @BeforeClass public static void bootstrap() { + net.minecraft.util.registry.Bootstrap.bootStrap(); + } + + @Test public void nearerTerrainRejectsTargetsBehindItOnEveryAxis() { + Vector3d origin = Vector3d.ZERO; + for (Direction direction : Direction.values()) { + Vector3d ray = new Vector3d(direction.getStepX(), direction.getStepY(), direction.getStepZ()); + assertFalse(direction.toString(), MusketItem.rayHitBeforeTerrain(origin, ray.scale(3), around(ray.scale(5))).isPresent()); + Optional hit = MusketItem.rayHitBeforeTerrain(origin, ray.scale(8), around(ray.scale(5))); + assertTrue(direction.toString(), hit.isPresent()); + assertEquals(4.5 * 4.5, origin.distanceToSqr(hit.get()), 0.000001); + } + } + + @Test public void terrainWinsAnExactTieWithTheEntitySurface() { + assertFalse(MusketItem.rayHitBeforeTerrain(Vector3d.ZERO, new Vector3d(0, 0, 4.5), + around(new Vector3d(0, 0, 5))).isPresent()); + } + + @Test public void finiteSegmentRejectsOffRayBehindAndBeyondRangeTargets() { + Vector3d end = new Vector3d(0, 0, 64); + assertFalse(MusketItem.rayHitBeforeTerrain(Vector3d.ZERO, end, around(new Vector3d(2, 0, 5))).isPresent()); + assertFalse(MusketItem.rayHitBeforeTerrain(Vector3d.ZERO, end, around(new Vector3d(0, 0, -5))).isPresent()); + assertFalse(MusketItem.rayHitBeforeTerrain(Vector3d.ZERO, end, around(new Vector3d(0, 0, 65))).isPresent()); + } + + @Test public void overlappingEntityStartsAtZeroDistance() { + Optional hit = MusketItem.rayHitBeforeTerrain(Vector3d.ZERO, new Vector3d(0, 0, 8), around(Vector3d.ZERO)); + assertTrue(hit.isPresent()); + assertEquals(Vector3d.ZERO, hit.get()); + } + + @Test public void targetingUsesLoadedServerEntitiesAndTerrainBeforeEntitySelection() throws Exception { + ClassNode node = new ClassNode(); + try (InputStream input = getClass().getResourceAsStream("/zone/moddev/mc/steamadvantage/items/MusketItem.class")) { + assertNotNull(input); + new ClassReader(input).accept(node, 0); + } + MethodNode trace = node.methods.stream().filter(method -> method.name.equals("rayTraceBlocksAndEntities")) + .findFirst().orElseThrow(() -> new AssertionError("Missing targeting method")); + boolean terrain = false, loadedEntities = false, boundedSelection = false, spectatorFilter = false; + for (AbstractInsnNode instruction : trace.instructions.toArray()) { + if (!(instruction instanceof MethodInsnNode)) continue; + MethodInsnNode call = (MethodInsnNode) instruction; + if (call.name.equals("clip")) terrain = true; + if (call.owner.equals("net/minecraft/world/server/ServerWorld") && call.name.equals("getAllEntities")) { + assertTrue("Terrain must be traced before selecting entities", terrain); + loadedEntities = true; + } + if (call.name.equals("rayHitBeforeTerrain")) boundedSelection = true; + if (call.name.equals("isSpectator")) spectatorFilter = true; + } + assertTrue("Server targeting must use the loaded-entity collection", loadedEntities); + assertTrue("Entity selection must be bounded by the actual terrain hit", boundedSelection); + assertTrue("Loaded-entity iteration must preserve the previous spectator exclusion", spectatorFilter); + } + + private static AxisAlignedBB around(Vector3d center) { + return new AxisAlignedBB(center.x - 0.5, center.y - 0.5, center.z - 0.5, + center.x + 0.5, center.y + 0.5, center.z + 0.5); + } +} diff --git a/src/test/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerFillPersistenceTest.java b/src/test/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerFillPersistenceTest.java new file mode 100644 index 0000000..be87d84 --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/machines/CoalBoilerFillPersistenceTest.java @@ -0,0 +1,219 @@ +package zone.moddev.mc.steamadvantage.machines; + +import static org.junit.Assert.*; + +import cyano.poweradvantage.api.ConduitType; +import zone.moddev.mc.poweradvantage.init.Fluids; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.world.World; +import cyano.poweradvantage.api.fluid.FluidStack; +import org.junit.BeforeClass; +import org.junit.Test; + +/** Save-notification unit witness; actual disk persistence is checked by the native restart rig. */ +public class CoalBoilerFillPersistenceTest { + @BeforeClass public static void bootstrap() { + net.minecraft.util.registry.Bootstrap.bootStrap(); + if (zone.moddev.mc.steamadvantage.init.Entities.STEAM_BOILER_COAL == null) + zone.moddev.mc.steamadvantage.init.Entities.STEAM_BOILER_COAL = net.minecraft.tileentity.TileEntityType.Builder.of(CoalBoilerTileEntity::new, net.minecraft.block.Blocks.STONE).build(null); + } + + @Test public void acceptingTheLastFiveMillibucketsRequestsSavingBeforeAnyTick() { + SaveWitnessBoiler boiler = seeded(3995); + FluidStack offered = new FluidStack(net.minecraft.fluid.Fluids.WATER, 5); + + assertEquals(5, boiler.fill(null, offered, true)); + assertEquals(4000, boiler.getTank().getFluidAmount()); + assertEquals(5, offered.amount); + assertSaved(boiler, 4000); + } + + @Test public void partialAcceptanceSavesOnlyTheQuantityActuallyAccepted() { + SaveWitnessBoiler boiler = seeded(3995); + FluidStack offered = new FluidStack(net.minecraft.fluid.Fluids.WATER, 100); + + assertEquals(5, boiler.fill(null, offered, true)); + assertEquals(4000, boiler.getTank().getFluidAmount()); + assertEquals(100, offered.amount); + assertSaved(boiler, 4000); + } + + @Test public void waterAcceptedThroughTheNetworkAlsoRequestsSavingImmediately() { + SaveWitnessBoiler boiler = seeded(3995); + ConduitType water = Fluids.fluidToConduitType(net.minecraft.fluid.Fluids.WATER); + + assertEquals(5, boiler.addEnergy(5, water), 0); + assertEquals(4000, boiler.getTank().getFluidAmount()); + assertSaved(boiler, 4000); + } + + @Test public void simulationNeitherChangesTheTankNorRequestsSaving() { + SaveWitnessBoiler boiler = seeded(3995); + FluidStack offered = new FluidStack(net.minecraft.fluid.Fluids.WATER, 100); + + assertEquals(5, boiler.fill(null, offered, false)); + assertEquals(3995, boiler.getTank().getFluidAmount()); + assertEquals(100, offered.amount); + assertUnchangedSave(boiler, 3995); + } + + @Test public void aFullTankRejectsInputWithoutRequestingSaving() { + SaveWitnessBoiler boiler = seeded(4000); + + assertEquals(0, boiler.fill(null, new FluidStack(net.minecraft.fluid.Fluids.WATER, 5), true)); + assertEquals(4000, boiler.getTank().getFluidAmount()); + assertUnchangedSave(boiler, 4000); + } + + @Test public void mismatchedFluidIsNotCreditedOrSaved() { + SaveWitnessBoiler boiler = seeded(3995); + FluidStack offered = new FluidStack(net.minecraft.fluid.Fluids.LAVA, 5); + + assertEquals(0, boiler.fill(null, offered, true)); + assertSame(net.minecraft.fluid.Fluids.WATER, boiler.getTank().getFluid().getFluid()); + assertEquals(3995, boiler.getTank().getFluidAmount()); + assertEquals(5, offered.amount); + assertUnchangedSave(boiler, 3995); + } + + @Test public void aZeroQuantityDoesNotRequestSaving() { + SaveWitnessBoiler boiler = seeded(3995); + + assertEquals(0, boiler.fill(null, new FluidStack(net.minecraft.fluid.Fluids.WATER, 0), true)); + assertEquals(3995, boiler.getTank().getFluidAmount()); + assertUnchangedSave(boiler, 3995); + } + + @Test public void theImmediateSaveWitnessRetainsFluidIdentityAndTypedNbt() { + SaveWitnessBoiler boiler = new SaveWitnessBoiler(); + FluidStack offered = new FluidStack(net.minecraft.fluid.Fluids.WATER, 5); + offered.tag = new CompoundNBT(); + offered.tag.putString("AdvWorksWitness", "external-fill-before-next-tick"); + offered.tag.putShort("TypedWitness", (short) 7); + CompoundNBT original = offered.tag.copy(); + boiler.rememberSavedTank(); + + assertEquals(5, boiler.fill(null, offered, true)); + assertSaved(boiler, 5); + FluidStack saved = FluidStack.loadFluidStackFromNBT(boiler.savedTank); + assertNotNull(saved); + assertSame(net.minecraft.fluid.Fluids.WATER, saved.getFluid()); + assertEquals(original, saved.tag); + assertEquals(original, offered.tag); + assertEquals(5, offered.amount); + } + + @Test public void emptyRequestedDrainReturnsNullWithoutDereferencingAMissingFluid() { + SaveWitnessBoiler boiler = new SaveWitnessBoiler(); + boiler.rememberSavedTank(); + assertNull(boiler.drain(null, new FluidStack(net.minecraft.fluid.Fluids.WATER, 5), true)); + assertNull(boiler.drain(null, new FluidStack(net.minecraft.fluid.Fluids.WATER, 5), false)); + assertEquals(0, boiler.dirtyCalls); + } + + @Test public void nullAndZeroRequestsNeitherMutateNorRequestSaving() { + SaveWitnessBoiler boiler = seeded(10); + assertEquals(0, boiler.fill(null, null, true)); + assertNull(boiler.drain(null, (FluidStack)null, true)); + assertNull(boiler.drain(null, new FluidStack(net.minecraft.fluid.Fluids.WATER, 0), true)); + assertNull(boiler.drain(null, 0, true)); + assertNull(boiler.drain(null, -1, true)); + assertEquals(10, boiler.getTank().getFluidAmount()); + assertUnchangedSave(boiler, 10); + } + + @Test public void mismatchedRequestedDrainReturnsNullRatherThanAZeroStack() { + SaveWitnessBoiler boiler = seeded(10); + assertNull(boiler.drain(null, new FluidStack(net.minecraft.fluid.Fluids.LAVA, 5), true)); + assertNull(boiler.drain(null, new FluidStack(net.minecraft.fluid.Fluids.LAVA, 5), false)); + assertEquals(10, boiler.getTank().getFluidAmount()); + assertUnchangedSave(boiler, 10); + } + + @Test public void nativeTankSimulationDoesNotRequestSaving() { + SaveWitnessBoiler boiler = seeded(10); + FluidStack preview = boiler.getTank().drain(5, false); + assertNotNull(preview); + assertEquals(5, preview.amount); + assertEquals(10, boiler.getTank().getFluidAmount()); + assertUnchangedSave(boiler, 10); + } + + @Test public void nativeRealTankDrainRequestsSavingEvenOutsideTheBoilerOverloads() { + SaveWitnessBoiler boiler = seeded(10); + FluidStack drained = boiler.getTank().drain(5, true); + assertNotNull(drained); + assertEquals(5, drained.amount); + assertEquals(5, boiler.getTank().getFluidAmount()); + assertSaved(boiler, 5); + } + + @Test public void aRealDrainToEmptySavesTheNativeEmptyTankRepresentation() { + SaveWitnessBoiler boiler = seeded(5); + assertEquals(5, boiler.drain(null, 5, true).amount); + assertEquals(0, boiler.getTank().getFluidAmount()); + assertSaved(boiler, 0); + assertNull(FluidStack.loadFluidStackFromNBT(boiler.savedTank)); + assertNull(boiler.drain(null, new FluidStack(net.minecraft.fluid.Fluids.WATER, 5), true)); + } + + @Test public void clientSideTankChangesDoNotRequestServerSaving() { + SaveWitnessBoiler boiler = seeded(3995); + boiler.saveWorld = world(true); + assertEquals(5, boiler.fill(null, new FluidStack(net.minecraft.fluid.Fluids.WATER, 5), true)); + assertEquals(4000, boiler.getTank().getFluidAmount()); + assertUnchangedSave(boiler, 3995); + } + + private static SaveWitnessBoiler seeded(int amount) { + SaveWitnessBoiler boiler = new SaveWitnessBoiler(); + boiler.getTank().setFluid(new FluidStack(net.minecraft.fluid.Fluids.WATER, amount)); + boiler.rememberSavedTank(); + return boiler; + } + + private static void assertSaved(SaveWitnessBoiler boiler, int amount) { + assertTrue("An accepted external fill must request saving without relying on a later tile tick", + boiler.dirtyCalls > 0); + assertEquals(amount, boiler.savedTank.getInt("Amount")); + } + + private static void assertUnchangedSave(SaveWitnessBoiler boiler, int amount) { + assertEquals(0, boiler.dirtyCalls); + assertEquals(amount, boiler.savedTank.getInt("Amount")); + } + + private static final class SaveWitnessBoiler extends CoalBoilerTileEntity { + int dirtyCalls; + CompoundNBT savedTank; + SaveWorld saveWorld = world(false); + @Override public World getLevel() { return saveWorld; } + void rememberSavedTank() { + dirtyCalls = 0; + savedTank = getTank().writeToNBT(new CompoundNBT()).copy(); + } + @Override public void setChanged() { + dirtyCalls++; + // Record only the notification payload; do not impersonate a native server save. + savedTank = getTank().writeToNBT(new CompoundNBT()).copy(); + } + } + + private static SaveWorld world(boolean remote) { + try { + Class allocator = Class.forName("sun.misc.Unsafe"); + java.lang.reflect.Field field = allocator.getDeclaredField("theUnsafe"); + field.setAccessible(true); + SaveWorld world = (SaveWorld) allocator.getMethod("allocateInstance", Class.class).invoke(field.get(null), SaveWorld.class); + java.lang.reflect.Field side = World.class.getDeclaredField("isClientSide"); + side.setAccessible(true); + side.setBoolean(world, remote); + return world; + } catch (ReflectiveOperationException failure) { + throw new AssertionError("Cannot prepare the save-notification world", failure); + } + } + private static final class SaveWorld extends net.minecraft.world.server.ServerWorld { + private SaveWorld() { super(null, null, null, null, null, null, null, null, false, 0L, java.util.Collections.emptyList(), false); } + } +} diff --git a/src/test/java/zone/moddev/mc/steamadvantage/machines/RockCrusherComparatorTest.java b/src/test/java/zone/moddev/mc/steamadvantage/machines/RockCrusherComparatorTest.java new file mode 100644 index 0000000..9130272 --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/machines/RockCrusherComparatorTest.java @@ -0,0 +1,25 @@ +package zone.moddev.mc.steamadvantage.machines; + +import static org.junit.Assert.assertEquals; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import org.junit.BeforeClass; +import org.junit.Test; + +public class RockCrusherComparatorTest { + @BeforeClass public static void bootstrap() { + net.minecraft.util.registry.Bootstrap.bootStrap(); + if (zone.moddev.mc.steamadvantage.init.Entities.STEAM_CRUSHER == null) + zone.moddev.mc.steamadvantage.init.Entities.STEAM_CRUSHER = net.minecraft.tileentity.TileEntityType.Builder.of(RockCrusherTileEntity::new, net.minecraft.block.Blocks.STONE).build(null); + } + @Test public void emptyInputHasNoComparatorSignal() { assertSignal(0, 0); } + @Test public void oneItemGivesSignalOne() { assertSignal(1, 1); } + @Test public void halfAStackGivesSignalEight() { assertSignal(32, 8); } + @Test public void aFullStackGivesSignalFifteen() { assertSignal(64, 15); } + + private static void assertSignal(int count, int expected) { + RockCrusherTileEntity crusher = new RockCrusherTileEntity(); + crusher.setItem(0, count == 0 ? ItemStack.EMPTY : new ItemStack(Items.COAL, count)); + assertEquals("Actual crusher comparator at " + count + " input items", expected, crusher.getComparatorOutput()); + } +} diff --git a/src/test/java/zone/moddev/mc/steamadvantage/machines/RockCrusherReloadRedstoneTest.java b/src/test/java/zone/moddev/mc/steamadvantage/machines/RockCrusherReloadRedstoneTest.java new file mode 100644 index 0000000..5145892 --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/machines/RockCrusherReloadRedstoneTest.java @@ -0,0 +1,92 @@ +package zone.moddev.mc.steamadvantage.machines; + +import static org.junit.Assert.*; +import java.lang.reflect.Field; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import org.junit.BeforeClass; +import org.junit.Test; + +public class RockCrusherReloadRedstoneTest { + @BeforeClass public static void bootstrap() { + net.minecraft.util.registry.Bootstrap.bootStrap(); + if (zone.moddev.mc.steamadvantage.init.Entities.STEAM_CRUSHER == null) + zone.moddev.mc.steamadvantage.init.Entities.STEAM_CRUSHER = net.minecraft.tileentity.TileEntityType.Builder.of(RockCrusherTileEntity::new, net.minecraft.block.Blocks.STONE).build(null); + if (zone.moddev.mc.steamadvantage.init.Entities.STEAM_FURNACE == null) + zone.moddev.mc.steamadvantage.init.Entities.STEAM_FURNACE = net.minecraft.tileentity.TileEntityType.Builder.of(BlastFurnaceTileEntity::new, net.minecraft.block.Blocks.STONE).build(null); + } + + @Test public void resumedWorkCannotBeDecrementedBeforeTheFirstLiveControlSample() throws Exception { + ProbeCrusher crusher = new ProbeCrusher(); + Field progress = RockCrusherTileEntity.class.getDeclaredField("progress"); + progress.setAccessible(true); + progress.setInt(crusher, 106); + crusher.testWorld = world(); + crusher.testWorld.stopAtFirstSample = true; + try { + crusher.tickUpdate(true); + fail("Live control must be sampled before touching loaded progress"); + } catch (ControlSample expected) { + assertEquals(106, progress.getInt(crusher)); + assertEquals(1, crusher.testWorld.samples); + } + } + + @Test public void scheduledPowerUpdateStillRefreshesTheInitializedCache() throws Exception { + ProbeCrusher crusher = new ProbeCrusher(); + crusher.testWorld = world(); + crusher.tickUpdate(true); + Field redstone = RockCrusherTileEntity.class.getDeclaredField("redstone"); + redstone.setAccessible(true); + assertFalse(redstone.getBoolean(crusher)); + crusher.testWorld.powered = true; + crusher.tickUpdate(true); + assertFalse(redstone.getBoolean(crusher)); + crusher.powerUpdate(); + assertTrue(redstone.getBoolean(crusher)); + assertEquals(2, crusher.testWorld.samples); + } + + @Test public void furnaceSamplesBeforeChangingItsRestoredHeatOrWork() throws Exception { + ProbeFurnace furnace = new ProbeFurnace(); + Field temperature = BlastFurnaceTileEntity.class.getDeclaredField("temperature"); + temperature.setAccessible(true); + temperature.setFloat(furnace, 1000); + furnace.testWorld = world(); + furnace.testWorld.stopAtFirstSample = true; + try { + furnace.tickUpdate(true); + fail("Live control must precede changes to loaded furnace heat or work"); + } catch (ControlSample expected) { + assertEquals(1000, temperature.getFloat(furnace), 0); + assertEquals(1, furnace.testWorld.samples); + } + } + + private static ControlWorld world() throws Exception { + Class allocator = Class.forName("sun.misc.Unsafe"); + Field field = allocator.getDeclaredField("theUnsafe"); + field.setAccessible(true); + return (ControlWorld) allocator.getMethod("allocateInstance", Class.class).invoke(field.get(null), ControlWorld.class); + } + private static final class ProbeCrusher extends RockCrusherTileEntity { + ControlWorld testWorld; + @Override public World getLevel() { return testWorld; } + } + private static final class ProbeFurnace extends BlastFurnaceTileEntity { + ControlWorld testWorld; + @Override public World getLevel() { return testWorld; } + } + private static final class ControlSample extends RuntimeException {} + private static final class ControlWorld extends ServerWorld { + boolean powered, stopAtFirstSample; + int samples; + private ControlWorld() { super(null, null, null, null, null, null, null, null, false, 0L, java.util.Collections.emptyList(), false); } + @Override public boolean hasNeighborSignal(BlockPos pos) { + samples++; + if (stopAtFirstSample) throw new ControlSample(); + return powered; + } + } +} diff --git a/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamOperationalPumpSourceTest.java b/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamOperationalPumpSourceTest.java new file mode 100644 index 0000000..6bcda79 --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamOperationalPumpSourceTest.java @@ -0,0 +1,150 @@ +package zone.moddev.mc.steamadvantage.machines; + +import java.io.InputStream; +import java.lang.reflect.Proxy; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.IBucketPickupHandler; +import net.minecraft.block.material.Material; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.FluidState; +import net.minecraft.fluid.Fluids; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; +import org.junit.BeforeClass; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TypeInsnNode; +import static org.junit.Assert.*; + +public class SteamOperationalPumpSourceTest { + private static final BlockPos SOURCE = new BlockPos(8, 80, 8); + + @BeforeClass public static void bootstrap() { + net.minecraft.util.registry.Bootstrap.bootStrap(); + } + + @Test public void nativePickupRetainsTheSlabAndOnlyClearsItsWater() { + BlockState wet = Blocks.OAK_SLAB.defaultBlockState().setValue(BlockStateProperties.WATERLOGGED, true); + PickupWorld world = new PickupWorld(wet); + assertSame(Fluids.WATER, SteamPumpTileEntity.pickupSource(world.world, SOURCE, wet)); + assertEquals(1, world.writes); + assertEquals(wet.setValue(BlockStateProperties.WATERLOGGED, false), world.state); + assertSame(Fluids.EMPTY, SteamPumpTileEntity.pickupSource(world.world, SOURCE, world.state)); + assertEquals("A dry host cannot produce another bucket", 1, world.writes); + } + + @Test public void nativePickupConsumesOrdinaryWaterAndLavaSources() { + for (Block block : new Block[]{Blocks.WATER, Blocks.LAVA}) { + BlockState source = block.defaultBlockState(); + PickupWorld world = new PickupWorld(source); + assertSame(source.getFluidState().getType(), SteamPumpTileEntity.pickupSource(world.world, SOURCE, source)); + assertEquals(1, world.writes); + assertEquals(Blocks.AIR.defaultBlockState(), world.state); + } + } + + @Test public void unsupportedModSourceIsNeverReplacedOrCredited() { + Block host = new Block(Block.Properties.of(Material.STONE)) { + @Override public FluidState getFluidState(BlockState state) { return Fluids.WATER.defaultFluidState(); } + }; + BlockState source = host.defaultBlockState(); + assertTrue(source.getFluidState().isSource()); + PickupWorld world = new PickupWorld(source); + assertSame(Fluids.EMPTY, SteamPumpTileEntity.pickupSource(world.world, SOURCE, source)); + assertSame(source, world.state); + assertEquals(0, world.writes); + } + + @Test public void flowingAndRefusedSourcesCannotProduceABucket() { + BlockState flowing = Blocks.WATER.defaultBlockState().setValue(BlockStateProperties.LEVEL, 1); + PickupWorld world = new PickupWorld(flowing); + assertSame(Fluids.EMPTY, SteamPumpTileEntity.pickupSource(world.world, SOURCE, flowing)); + assertEquals(0, world.writes); + RefusingSource host = new RefusingSource(); + BlockState refused = host.defaultBlockState(); + PickupWorld refusedWorld = new PickupWorld(refused); + assertSame(Fluids.EMPTY, SteamPumpTileEntity.pickupSource(refusedWorld.world, SOURCE, refused)); + assertSame(refused, refusedWorld.state); + assertEquals(0, refusedWorld.writes); + } + + @Test public void pumpUsesNativePickupBeforeCreditWithoutDestructiveFallback() throws Exception { + ClassNode node = new ClassNode(); + try (InputStream input = getClass().getResourceAsStream( + "/zone/moddev/mc/steamadvantage/machines/SteamPumpTileEntity.class")) { + assertNotNull(input); + new ClassReader(input).accept(node, 0); + } + MethodNode tick = method(node, "tickUpdate"), pickup = method(node, "pickupSource"); + int extraction = -1, fill = -1, index = 0; + boolean nativePickup = false, nativeGuard = false; + for (MethodNode candidate : new MethodNode[]{tick, pickup}) { + for (AbstractInsnNode instruction : candidate.instructions.toArray()) { + if (instruction instanceof FieldInsnNode) { + FieldInsnNode field = (FieldInsnNode) instruction; + assertFalse("Caller must not erase waterlogged hosts with AIR", + field.getOpcode() == Opcodes.GETSTATIC && field.owner.equals("net/minecraft/block/Blocks") + && field.name.equals("AIR")); + } else if (instruction instanceof TypeInsnNode) { + TypeInsnNode type = (TypeInsnNode) instruction; + if (type.getOpcode() == Opcodes.INSTANCEOF && type.desc.equals("net/minecraft/block/IBucketPickupHandler")) nativeGuard = true; + } else if (instruction instanceof MethodInsnNode) { + MethodInsnNode call = (MethodInsnNode) instruction; + assertFalse("No destructive fallback when native pickup is unavailable", + call.name.equals("removeBlock") || call.name.equals("destroyBlock")); + if (candidate == pickup) { + assertFalse("Pickup policy delegates block mutation to the native handler", + call.name.equals("setBlock") || call.name.equals("setBlockAndUpdate")); + if (call.owner.equals("net/minecraft/block/IBucketPickupHandler") && call.name.equals("takeLiquid")) nativePickup = true; + } else { + if (call.name.equals("pickupSource")) extraction = index; + if (call.owner.equals("cyano/poweradvantage/api/fluid/FluidTank") && call.name.equals("fill")) fill = index; + } + } + index++; + } + } + assertTrue("Unsupported blocks are rejected before native pickup", nativeGuard && nativePickup); + assertTrue("Successful native pickup precedes the final bucket credit", extraction >= 0 && fill > extraction); + } + + private static MethodNode method(ClassNode node, String name) { + return node.methods.stream().filter(method -> method.name.equals(name)).findFirst() + .orElseThrow(() -> new AssertionError("Missing pump method " + name)); + } + + private static final class RefusingSource extends Block implements IBucketPickupHandler { + private RefusingSource() { super(Block.Properties.of(Material.STONE)); } + @Override public FluidState getFluidState(BlockState state) { return Fluids.WATER.defaultFluidState(); } + @Override public Fluid takeLiquid(IWorld world, BlockPos pos, BlockState state) { return Fluids.EMPTY; } + } + + private static final class PickupWorld { + private BlockState state; + private int writes; + private final IWorld world; + + private PickupWorld(BlockState initial) { + state = initial; + world = (IWorld) Proxy.newProxyInstance(IWorld.class.getClassLoader(), new Class[]{IWorld.class}, + (proxy, method, arguments) -> { + if (method.getName().equals("setBlock")) { + assertEquals(SOURCE, arguments[0]); + state = (BlockState) arguments[1]; + writes++; + return true; + } + throw new AssertionError("Unexpected native pickup world call: " + method.getName()); + }); + } + } +} diff --git a/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamOperationalStillCapacityTest.java b/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamOperationalStillCapacityTest.java new file mode 100644 index 0000000..1bb617f --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/machines/SteamOperationalStillCapacityTest.java @@ -0,0 +1,91 @@ +package zone.moddev.mc.steamadvantage.machines; + +import cyano.poweradvantage.api.fluid.FluidStack; +import java.lang.reflect.Method; +import net.minecraft.block.Blocks; +import net.minecraft.fluid.Fluids; +import net.minecraft.tileentity.TileEntityType; +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 zone.moddev.mc.steamadvantage.init.Entities; +import static org.junit.Assert.*; + +/** Pure capacity planning; native operating regressions live in SteamOperationalCases. */ +public class SteamOperationalStillCapacityTest { + @BeforeClass public static void bootstrap() { + net.minecraft.util.registry.Bootstrap.bootStrap(); + if (Entities.STEAM_STILL == null) { + Entities.STEAM_STILL = TileEntityType.Builder.of(SteamStillTileEntity::new, Blocks.STONE).build(null); + } + } + + @Test public void fullOutputCannotPlanOrDebitAnyInput() throws Exception { + SteamStillTileEntity still = still(1000); + FluidStack input = new FluidStack(Fluids.WATER, 200); + assertEquals(0, plan(still, recipe(2, 1), input)); + assertEquals(200, input.amount); + assertEquals(1000, still.getOutputTank().getFluidAmount()); + } + + @Test public void oneOutputSpacePlansOnlyOneApplicationWithoutMutatingEitherTank() throws Exception { + SteamStillTileEntity still = still(999); + FluidStack input = new FluidStack(Fluids.WATER, 200); + assertEquals(1, plan(still, recipe(2, 1), input)); + assertEquals(200, input.amount); + assertEquals(999, still.getOutputTank().getFluidAmount()); + } + + @Test public void normalSpeedPlansTwoApplicationsWhenBothProductsFit() throws Exception { + SteamStillTileEntity still = still(998); + FluidStack input = new FluidStack(Fluids.WATER, 200); + assertEquals(2, plan(still, recipe(2, 1), input)); + assertEquals(200, input.amount); + assertEquals(998, still.getOutputTank().getFluidAmount()); + } + + @Test public void incompleteInputCannotPlanProduct() throws Exception { + SteamStillTileEntity still = still(0); + FluidStack input = new FluidStack(Fluids.WATER, 1); + assertEquals(0, plan(still, recipe(2, 1), input)); + assertEquals(1, input.amount); + assertEquals(0, still.getOutputTank().getFluidAmount()); + } + + @Test public void mismatchedProductIsNotOverwritten() throws Exception { + SteamStillTileEntity still = new SteamStillTileEntity(); + still.getOutputTank().setFluid(new FluidStack(Fluids.WATER, 10)); + FluidStack input = new FluidStack(Fluids.WATER, 200); + assertEquals(0, plan(still, recipe(2, 1), input)); + assertEquals(200, input.amount); + assertSame(Fluids.WATER, still.getOutputTank().getFluid().getFluid()); + assertEquals(10, still.getOutputTank().getFluidAmount()); + } + + @Test public void multiMillibucketProductMustFitAsAWhole() throws Exception { + FluidStack input = new FluidStack(Fluids.WATER, 200); + assertEquals(0, plan(still(997), recipe(3, 4), input)); + assertEquals(1, plan(still(996), recipe(3, 4), input)); + assertEquals(2, plan(still(992), recipe(3, 4), input)); + assertEquals(200, input.amount); + } + + private static SteamStillTileEntity still(int output) { + SteamStillTileEntity still = new SteamStillTileEntity(); + if (output > 0) still.getOutputTank().setFluid(new FluidStack(Fluids.LAVA, output)); + return still; + } + + private static DistillationRecipe recipe(int in, int out) { + return new DistillationRecipe(new ExplicitFluidReference(Fluids.WATER), in, + new ExplicitFluidReference(Fluids.LAVA), out); + } + + private static int plan(SteamStillTileEntity still, DistillationRecipe recipe, FluidStack input) throws Exception { + Method method = SteamStillTileEntity.class.getDeclaredMethod("distillationApplications", + DistillationRecipe.class, FluidStack.class); + method.setAccessible(true); + return (Integer) method.invoke(still, recipe, input); + } +} diff --git a/src/test/java/zone/moddev/mc/steamadvantage/machines/WaterBoilerFluidBoundaryTest.java b/src/test/java/zone/moddev/mc/steamadvantage/machines/WaterBoilerFluidBoundaryTest.java new file mode 100644 index 0000000..b0b3fa7 --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/machines/WaterBoilerFluidBoundaryTest.java @@ -0,0 +1,166 @@ +package zone.moddev.mc.steamadvantage.machines; + +import static org.junit.Assert.*; +import java.lang.reflect.Method; +import java.util.*; +import net.minecraft.nbt.CompoundNBT; +import cyano.poweradvantage.api.fluid.FluidStack; +import cyano.poweradvantage.api.fluid.FluidTank; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/** Calls each actual boiler method; no stand-in fill/drain implementation or world ticks. */ +@RunWith(Parameterized.class) +public class WaterBoilerFluidBoundaryTest { + @Parameterized.Parameters(name = "{0}") + public static Collection boilers() { + return Arrays.asList(new Object[][]{{CoalBoilerTileEntity.class}, + {ElectricBoilerTileEntity.class}, {GeothermalBoilerTileEntity.class}}); + } + private final Class type; + private Object boiler; + private FluidTank tank; + public WaterBoilerFluidBoundaryTest(Class type) { this.type = type; } + @BeforeClass public static void bootstrap() { + net.minecraft.util.registry.Bootstrap.bootStrap(); + if (zone.moddev.mc.steamadvantage.init.Entities.STEAM_BOILER_COAL == null) + zone.moddev.mc.steamadvantage.init.Entities.STEAM_BOILER_COAL = net.minecraft.tileentity.TileEntityType.Builder.of(CoalBoilerTileEntity::new, net.minecraft.block.Blocks.STONE).build(null); + if (zone.moddev.mc.steamadvantage.init.Entities.STEAM_BOILER_ELECTRIC == null) + zone.moddev.mc.steamadvantage.init.Entities.STEAM_BOILER_ELECTRIC = net.minecraft.tileentity.TileEntityType.Builder.of(ElectricBoilerTileEntity::new, net.minecraft.block.Blocks.STONE).build(null); + if (zone.moddev.mc.steamadvantage.init.Entities.STEAM_BOILER_GEOTHERMAL == null) + zone.moddev.mc.steamadvantage.init.Entities.STEAM_BOILER_GEOTHERMAL = net.minecraft.tileentity.TileEntityType.Builder.of(GeothermalBoilerTileEntity::new, net.minecraft.block.Blocks.STONE).build(null); + } + @Before public void createActualBoiler() throws Exception { + boiler = type.getConstructor().newInstance(); + tank = (FluidTank) type.getMethod("getTank").invoke(boiler); + } + + @Test public void emptyTankRejectsLavaInSimulationAndExecutionWithoutChangingTheOffer() throws Exception { + for (boolean execute : new boolean[]{false, true}) { + stock(0); + FluidStack lava = new FluidStack(net.minecraft.fluid.Fluids.LAVA, 5); + CompoundNBT original = lava.writeToNBT(new CompoundNBT()).copy(); + assertEquals(Boolean.FALSE, type.getMethod("canFill", net.minecraft.util.Direction.class, net.minecraft.fluid.Fluid.class).invoke(boiler, null, net.minecraft.fluid.Fluids.LAVA)); + assertEquals(0, fill(lava, execute)); + assertEquals(0, tank.getFluidAmount()); + assertEquals(original, lava.writeToNBT(new CompoundNBT())); + } + } + + @Test public void emptyTankStillAcceptsWaterWithoutChangingTheOffer() throws Exception { + FluidStack offered = new FluidStack(net.minecraft.fluid.Fluids.WATER, 5); + CompoundNBT original = offered.writeToNBT(new CompoundNBT()).copy(); + assertEquals(Boolean.TRUE, type.getMethod("canFill", net.minecraft.util.Direction.class, net.minecraft.fluid.Fluid.class).invoke(boiler, null, net.minecraft.fluid.Fluids.WATER)); + assertEquals(5, fill(offered, true)); + assertEquals(5, tank.getFluidAmount()); + assertSame(net.minecraft.fluid.Fluids.WATER, tank.getFluid().getFluid()); + assertEquals(original, offered.writeToNBT(new CompoundNBT())); + } + + @Test public void seededTankRejectsMismatchedFillAndDrain() throws Exception { + stock(100); + FluidStack lava = new FluidStack(net.minecraft.fluid.Fluids.LAVA, 5); + CompoundNBT original = lava.writeToNBT(new CompoundNBT()).copy(); + for (boolean execute : new boolean[]{false, true}) { + assertEquals(0, fill(lava, execute)); + assertNull(drain(lava, execute)); + } + assertEquals(100, tank.getFluidAmount()); + assertSame(net.minecraft.fluid.Fluids.WATER, tank.getFluid().getFluid()); + assertEquals(original, lava.writeToNBT(new CompoundNBT())); + } + + @Test public void nullFillIsSafeOnEmptyAndSeededTanks() throws Exception { + for (int amount : new int[]{0, 100}) { + stock(amount); + assertEquals(0, fill(null, false)); + assertEquals(0, fill(null, true)); + assertEquals(amount, tank.getFluidAmount()); + } + } + + @Test public void zeroAndNegativeFillsDoNotChangeTheTank() throws Exception { + stock(100); + for (int amount : new int[]{0, -5}) { + FluidStack request = new FluidStack(net.minecraft.fluid.Fluids.WATER, amount); + request.amount = amount; + assertEquals(0, fill(request, false)); + assertEquals(0, fill(request, true)); + } + assertEquals(100, tank.getFluidAmount()); + } + + @Test public void typedDrainOnAnEmptyTankReturnsNull() throws Exception { + assertNull(drain(new FluidStack(net.minecraft.fluid.Fluids.WATER, 5), false)); + assertNull(drain(new FluidStack(net.minecraft.fluid.Fluids.WATER, 5), true)); + assertEquals(0, tank.getFluidAmount()); + } + + @Test public void nullTypedDrainIsSafeOnEmptyAndSeededTanks() throws Exception { + for (int amount : new int[]{0, 100}) { + stock(amount); + assertNull(drain((FluidStack)null, false)); + assertNull(drain((FluidStack)null, true)); + assertEquals(amount, tank.getFluidAmount()); + } + } + + @Test public void zeroAndNegativeTypedDrainsReturnNull() throws Exception { + stock(100); + for (int amount : new int[]{0, -5}) { + FluidStack request = new FluidStack(net.minecraft.fluid.Fluids.WATER, amount); + request.amount = amount; + assertNull(drain(request, false)); + assertNull(drain(request, true)); + } + assertEquals(100, tank.getFluidAmount()); + } + + @Test public void zeroAndNegativeAmountDrainsReturnNull() throws Exception { + stock(100); + for (int amount : new int[]{0, -5}) { + assertNull(drain(amount, false)); + assertNull(drain(amount, true)); + } + assertEquals(100, tank.getFluidAmount()); + } + + @Test public void matchingSimulationKeepsAllStockAndTheFiniteRequestUnchanged() throws Exception { + stock(100); + FluidStack request = new FluidStack(net.minecraft.fluid.Fluids.WATER, 5); + CompoundNBT original = request.writeToNBT(new CompoundNBT()).copy(); + assertEquals(5, fill(request, false)); + assertEquals(5, drain(request, false).amount); + assertEquals(5, drain(5, false).amount); + assertEquals(100, tank.getFluidAmount()); + assertEquals(original, request.writeToNBT(new CompoundNBT())); + } + + @Test public void aRealMatchingDrainReturnsOnlyTheRequestedWater() throws Exception { + stock(100); + FluidStack request = new FluidStack(net.minecraft.fluid.Fluids.WATER, 5); + FluidStack result = drain(request, true); + assertNotNull(result); + assertSame(net.minecraft.fluid.Fluids.WATER, result.getFluid()); + assertEquals(5, result.amount); + assertEquals(95, tank.getFluidAmount()); + assertEquals(5, request.amount); + } + + private void stock(int amount) { tank.setFluid(amount == 0 ? null : new FluidStack(net.minecraft.fluid.Fluids.WATER, amount)); } + private int fill(FluidStack offered, boolean execute) throws Exception { + Method method = type.getMethod("fill", net.minecraft.util.Direction.class, FluidStack.class, boolean.class); + return ((Number) method.invoke(boiler, null, offered, execute)).intValue(); + } + private FluidStack drain(FluidStack request, boolean execute) throws Exception { + return (FluidStack) type.getMethod("drain", net.minecraft.util.Direction.class, FluidStack.class, boolean.class) + .invoke(boiler, null, request, execute); + } + private FluidStack drain(int amount, boolean execute) throws Exception { + return (FluidStack) type.getMethod("drain", net.minecraft.util.Direction.class, int.class, boolean.class) + .invoke(boiler, null, amount, execute); + } +} diff --git a/src/test/java/zone/moddev/mc/steamadvantage/machines/WaterBoilerTankNotificationTest.java b/src/test/java/zone/moddev/mc/steamadvantage/machines/WaterBoilerTankNotificationTest.java new file mode 100644 index 0000000..23213de --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/machines/WaterBoilerTankNotificationTest.java @@ -0,0 +1,165 @@ +package zone.moddev.mc.steamadvantage.machines; + +import static org.junit.Assert.*; +import cyano.poweradvantage.api.IPowerMachine; +import zone.moddev.mc.poweradvantage.init.Fluids; +import java.util.*; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.world.World; +import cyano.poweradvantage.api.fluid.FluidStack; +import cyano.poweradvantage.api.fluid.FluidTank; +import org.junit.BeforeClass; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/** Save notifications only; native restart reports remain the disk-persistence evidence. */ +@RunWith(Parameterized.class) +public class WaterBoilerTankNotificationTest { + @Parameterized.Parameters(name = "{0}") + public static Collection boilers() { return Arrays.asList(new Object[][]{{"electric"}, {"geothermal"}}); } + private final String type; + private Probe probe; + public WaterBoilerTankNotificationTest(String type) { this.type = type; } + @BeforeClass public static void bootstrap() { + net.minecraft.util.registry.Bootstrap.bootStrap(); + if (zone.moddev.mc.steamadvantage.init.Entities.STEAM_BOILER_ELECTRIC == null) + zone.moddev.mc.steamadvantage.init.Entities.STEAM_BOILER_ELECTRIC = net.minecraft.tileentity.TileEntityType.Builder.of(ElectricBoilerTileEntity::new, net.minecraft.block.Blocks.STONE).build(null); + if (zone.moddev.mc.steamadvantage.init.Entities.STEAM_BOILER_GEOTHERMAL == null) + zone.moddev.mc.steamadvantage.init.Entities.STEAM_BOILER_GEOTHERMAL = net.minecraft.tileentity.TileEntityType.Builder.of(GeothermalBoilerTileEntity::new, net.minecraft.block.Blocks.STONE).build(null); + } + @Before public void createRealBoiler() { + probe = type.equals("electric") ? new ElectricProbe() : new GeothermalProbe(); + probe.save().remember(probe.tank()); + } + + @Test public void publicAcceptedFillRequestsSavingBeforeAnyTick() throws Exception { + FluidStack offer = water(5); + assertEquals(5, fill(offer, true)); + assertEquals(5, offer.amount); + saved(5); + } + + @Test public void networkAcceptedWaterAlsoRequestsSavingBeforeAnyTick() { + assertEquals(5, probe.machine().addEnergy(5, Fluids.fluidToConduitType(net.minecraft.fluid.Fluids.WATER)), 0); + saved(5); + } + + @Test public void directTankFillUsesTheSameOwnerNotification() { + assertEquals(5, probe.tank().fill(water(5), true)); + saved(5); + } + + @Test public void publicRealDrainRequestsSaving() throws Exception { + stock(10); + assertEquals(5, drain(5, true).amount); + saved(5); + } + + @Test public void directRealDrainUsesTheSameOwnerNotification() { + stock(10); + assertEquals(5, probe.tank().drain(5, true).amount); + saved(5); + } + + @Test public void drainingToEmptyRequestsSavingOfTheNativeEmptyRepresentation() { + stock(5); + assertEquals(5, probe.tank().drain(5, true).amount); + saved(0); + assertNull(FluidStack.loadFluidStackFromNBT(probe.save().savedTank)); + } + + @Test public void directAndPublicSimulationsNeverRequestSaving() throws Exception { + stock(10); + assertEquals(5, probe.tank().fill(water(5), false)); + assertEquals(5, probe.tank().drain(5, false).amount); + assertEquals(5, fill(water(5), false)); + assertEquals(5, drain(5, false).amount); + unchanged(10); + } + + @Test public void aClientFillChangesOnlyItsLocalTankWithoutRequestingServerSaving() throws Exception { + stock(10); probe.side(true); + assertEquals(5, fill(water(5), true)); + assertEquals(15, probe.tank().getFluidAmount()); + assertEquals(0, probe.save().dirtyCalls); + assertEquals(10, probe.save().savedTank.getInt("Amount")); + } + + @Test public void aClientDirectDrainDoesNotRequestServerSaving() { + stock(10); probe.side(true); + assertEquals(5, probe.tank().drain(5, true).amount); + assertEquals(5, probe.tank().getFluidAmount()); + assertEquals(0, probe.save().dirtyCalls); + assertEquals(10, probe.save().savedTank.getInt("Amount")); + } + + private static FluidStack water(int amount) { return new FluidStack(net.minecraft.fluid.Fluids.WATER, amount); } + private void stock(int amount) { probe.tank().setFluid(water(amount)); probe.save().remember(probe.tank()); } + private void saved(int amount) { + assertTrue("Real server-side tank mutation must notify its owner immediately", probe.save().dirtyCalls > 0); + assertEquals(amount, probe.tank().getFluidAmount()); + assertEquals(amount, probe.save().savedTank.getInt("Amount")); + } + private void unchanged(int amount) { + assertEquals(0, probe.save().dirtyCalls); + assertEquals(amount, probe.tank().getFluidAmount()); + assertEquals(amount, probe.save().savedTank.getInt("Amount")); + } + private int fill(FluidStack offer, boolean execute) throws Exception { + return ((Number) probe.machine().getClass().getMethod("fill", net.minecraft.util.Direction.class, FluidStack.class, boolean.class) + .invoke(probe.machine(), null, offer, execute)).intValue(); + } + private FluidStack drain(int amount, boolean execute) throws Exception { + return (FluidStack) probe.machine().getClass().getMethod("drain", net.minecraft.util.Direction.class, int.class, boolean.class) + .invoke(probe.machine(), null, amount, execute); + } + private interface Probe { + FluidTank tank(); + SaveWitness save(); + IPowerMachine machine(); + void side(boolean client); + } + private static final class SaveWitness { + int dirtyCalls; + CompoundNBT savedTank; + void remember(FluidTank tank) { dirtyCalls = 0; savedTank = tank.writeToNBT(new CompoundNBT()).copy(); } + void changed(FluidTank tank) { dirtyCalls++; savedTank = tank.writeToNBT(new CompoundNBT()).copy(); } + } + private static final class ElectricProbe extends ElectricBoilerTileEntity implements Probe { + private final SaveWitness witness = new SaveWitness(); + private World testWorld = world(false); + @Override public World getLevel() { return testWorld; } + @Override public void setChanged() { witness.changed(getTank()); } + @Override public FluidTank tank() { return getTank(); } + @Override public SaveWitness save() { return witness; } + @Override public IPowerMachine machine() { return this; } + @Override public void side(boolean client) { testWorld = world(client); } + } + private static final class GeothermalProbe extends GeothermalBoilerTileEntity implements Probe { + private final SaveWitness witness = new SaveWitness(); + private World testWorld = world(false); + @Override public World getLevel() { return testWorld; } + @Override public void setChanged() { witness.changed(getTank()); } + @Override public FluidTank tank() { return getTank(); } + @Override public SaveWitness save() { return witness; } + @Override public IPowerMachine machine() { return this; } + @Override public void side(boolean client) { testWorld = world(client); } + } + private static World world(boolean client) { + try { + Class allocator = Class.forName("sun.misc.Unsafe"); + java.lang.reflect.Field field = allocator.getDeclaredField("theUnsafe"); + field.setAccessible(true); + SaveWorld world = (SaveWorld) allocator.getMethod("allocateInstance", Class.class).invoke(field.get(null), SaveWorld.class); + java.lang.reflect.Field clientField = World.class.getDeclaredField("isClientSide"); + clientField.setAccessible(true); + clientField.setBoolean(world, client); + return world; + } catch (ReflectiveOperationException failure) { throw new AssertionError(failure); } + } + private static final class SaveWorld extends net.minecraft.world.server.ServerWorld { + private SaveWorld() { super(null, null, null, null, null, null, null, null, false, 0L, java.util.Collections.emptyList(), false); } + } +} diff --git a/src/test/java/zone/moddev/mc/steamadvantage/util/SoundHelperLoadedPlayersTest.java b/src/test/java/zone/moddev/mc/steamadvantage/util/SoundHelperLoadedPlayersTest.java new file mode 100644 index 0000000..ec74fd1 --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/util/SoundHelperLoadedPlayersTest.java @@ -0,0 +1,128 @@ +package zone.moddev.mc.steamadvantage.util; + +import java.io.InputStream; +import net.minecraft.util.math.AxisAlignedBB; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TypeInsnNode; +import static org.junit.Assert.*; + +public class SoundHelperLoadedPlayersTest { + @Test public void soundDispatchNeverScansEntitiesOrLoadsChunks() throws Exception { + int loadedPlayerIterations = 0; + for (MethodNode method : soundHelper().methods) { + for (AbstractInsnNode instruction : method.instructions.toArray()) { + if (!(instruction instanceof MethodInsnNode)) continue; + MethodInsnNode call = (MethodInsnNode) instruction; + assertFalse("Entity query reintroduced in " + method.name, + call.name.equals("getEntitiesOfClass") || call.name.equals("getEntities")); + assertFalse("Chunk query reintroduced in " + method.name, + call.name.startsWith("getChunk") || call.name.equals("getLoadedChunk")); + if (call.name.equals("players")) loadedPlayerIterations++; + } + } + assertEquals("Both sound ranges must iterate the existing loaded-player list", 2, loadedPlayerIterations); + } + + @Test public void bothRangesKeepBoundsServerPlayerAndConnectionGuards() throws Exception { + verifyDispatch("playSoundAtPosition", 16); + verifyDispatch("playBigSoundAtPosition", 50); + } + + @Test public void bothSoundRangesExplicitlyExcludeSpectatorsBeforeSending() throws Exception { + int checked = 0; + for (MethodNode method : soundHelper().methods) { + if (!method.name.equals("playSoundAtPosition") && !method.name.equals("playBigSoundAtPosition")) continue; + int predicate = -1, tested = -1, packet = -1; + for (AbstractInsnNode instruction : method.instructions.toArray()) { + if (instruction instanceof FieldInsnNode) { + FieldInsnNode field = (FieldInsnNode) instruction; + if (field.getOpcode() == Opcodes.GETSTATIC && field.owner.equals("net/minecraft/util/EntityPredicates") + && field.name.equals("NO_SPECTATORS")) predicate = method.instructions.indexOf(instruction); + } else if (instruction instanceof MethodInsnNode) { + MethodInsnNode call = (MethodInsnNode) instruction; + if (call.owner.equals("java/util/function/Predicate") && call.name.equals("test")) { + tested = method.instructions.indexOf(instruction); + AbstractInsnNode guard = instruction.getNext(); + while (guard != null && guard.getOpcode() < 0) guard = guard.getNext(); + assertTrue(method.name + " rejects a false native spectator predicate", + guard instanceof JumpInsnNode && guard.getOpcode() == Opcodes.IFEQ); + } + if (call.owner.equals("net/minecraft/network/play/server/SPlaySoundPacket") && call.name.equals("")) { + packet = method.instructions.indexOf(instruction); + } + } + } + assertTrue(method.name + " applies native NO_SPECTATORS before creating the sound packet", + predicate >= 0 && tested > predicate && packet > tested); + checked++; + } + assertEquals("Both sound ranges preserve spectator exclusion", 2, checked); + } + + @Test public void rangeSelectionKeepsStrictAabbOverlapNotDistanceOrPlayerCenter() { + for (double radius : new double[]{16, 50}) { + AxisAlignedBB area = new AxisAlignedBB(-radius, -radius, -radius, radius, radius, radius); + assertTrue("An overlapping player body is included even with its center outside the cube", + area.intersects(new AxisAlignedBB(radius - 0.1, -0.5, -0.3, radius + 0.5, 1.3, 0.3))); + assertTrue("Corner overlap remains included, not replaced with a spherical radius", + area.intersects(new AxisAlignedBB(radius - 0.1, radius - 0.1, radius - 0.1, + radius + 0.5, radius + 1.7, radius + 0.5))); + assertFalse("Merely touching the positive boundary is not an intersection", + area.intersects(new AxisAlignedBB(radius, -0.5, -0.3, radius + 0.6, 1.3, 0.3))); + assertFalse("Merely touching the negative boundary is not an intersection", + area.intersects(new AxisAlignedBB(-radius - 0.6, -0.5, -0.3, -radius, 1.3, 0.3))); + } + } + + private static void verifyDispatch(String name, double radius) throws Exception { + MethodNode method = soundHelper().methods.stream().filter(candidate -> candidate.name.equals(name)) + .findFirst().orElseThrow(() -> new AssertionError("Missing sound dispatch " + name)); + int playerLists = 0, bounds = 0, intersections = 0, soundPackets = 0; + boolean correctRadius = false, serverPlayer = false, connection = false, nullGuard = false; + for (AbstractInsnNode instruction : method.instructions.toArray()) { + if (instruction instanceof MethodInsnNode) { + MethodInsnNode call = (MethodInsnNode) instruction; + if (call.name.equals("players")) playerLists++; + if (call.name.equals("getBoundingBox")) bounds++; + if (call.owner.equals("net/minecraft/util/math/AxisAlignedBB") && call.name.equals("intersects") + && call.desc.equals("(Lnet/minecraft/util/math/AxisAlignedBB;)Z")) intersections++; + if (call.owner.equals("net/minecraft/network/play/server/SPlaySoundPacket") && call.name.equals("")) soundPackets++; + } else if (instruction instanceof LdcInsnNode) { + Object value = ((LdcInsnNode) instruction).cst; + if (value instanceof Double && ((Double) value).doubleValue() == radius) correctRadius = true; + } else if (instruction instanceof TypeInsnNode) { + TypeInsnNode type = (TypeInsnNode) instruction; + if (type.getOpcode() == Opcodes.INSTANCEOF && type.desc.equals("net/minecraft/entity/player/ServerPlayerEntity")) serverPlayer = true; + } else if (instruction instanceof FieldInsnNode) { + FieldInsnNode field = (FieldInsnNode) instruction; + if (field.getOpcode() == Opcodes.GETFIELD && field.name.equals("connection")) connection = true; + } else if (instruction instanceof JumpInsnNode && instruction.getOpcode() == Opcodes.IFNULL) nullGuard = true; + } + assertEquals(name, 1, playerLists); + assertEquals(name, 1, bounds); + assertEquals(name, 1, intersections); + assertEquals(name, 1, soundPackets); + assertTrue(name + " keeps its exact range", correctRadius); + assertTrue(name + " requires a server player", serverPlayer); + assertTrue(name + " guards the connection before sending", connection && nullGuard); + } + + private static ClassNode soundHelper() throws Exception { + ClassNode node = new ClassNode(); + try (InputStream input = SoundHelperLoadedPlayersTest.class.getResourceAsStream( + "/zone/moddev/mc/steamadvantage/util/SoundHelper.class")) { + assertNotNull("Compiled SoundHelper is available", input); + new ClassReader(input).accept(node, 0); + } + return node; + } +} From a454f480f493a911a6d9d320d69ef26886d3f4d2 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Fri, 30 Oct 2026 20:57:39 +0000 Subject: [PATCH 9/9] Clarify Steam Advantage source port status --- README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 956fc6f..29ef05b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # SteamAdvantage -**Minecraft 1.16.5 port candidate, version 2.2.8.116051.** -This branch is a local candidate pending manual acceptance and publication approval. +**Minecraft 1.16.5 source port candidate, version 2.2.8.116051.** +This source port remains pending manual acceptance and publication approval. The follow-up checks use finite supplies and ordinary server ticks to measure actual machine output, energy use, blocked routes and saved state. They also cover fluid pickup without destroying waterlogged blocks. Rendered GUI checks @@ -11,8 +11,7 @@ earlier results are retained separately rather than counted again. Earlier-candidate results and accepted 1.15 results do not qualify this candidate. 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. Steam Advantage adds steam-powered machines and infrastructure to Power Advantage. @@ -24,14 +23,14 @@ ForgeGradle 7.0.34 and Gradle 9.6.1 run on Temurin 17.0.1+12. Compilation and Minecraft launches use Temurin 8.0.502+7 and Java 8 bytecode; Mavenizer uses Temurin 25.0.3+9.0.LTS. -Power Advantage 2.4.7.116051 remains a separate required mod. The current local -candidate uses source `bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7`. +Power Advantage 2.4.7.116051 remains a separate required mod. The pinned compile +dependency uses source `bcb75bfa91c14751ebf1e31865e1ec0ffa82c0b7`. Its development jar SHA-256 is `2FB923944A456B4F26AB2F9212C646469CE3F49BFD4DAE894C15559B48908386`. These exact pins are recorded in `gradle.properties` and audited during builds. Use an immutable development jar through `-PpowerAdvantageDeobfJar=`. Release audits reject missing, placeholder, or mismatched pins. These source pins -are local candidates, not publication approval. +do not grant publication approval. Power's migration hook preserves legacy Forge swimming speed, nametag distance, gravity and reach attributes, including their values and modifiers. Steam uses