diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 80c3d53..a7ab631 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,16 +1,16 @@ -name: Steam Advantage 1.14 CI +name: Steam Advantage 1.15 CI on: push: - branches: [master-1.14.4, 'feature/**'] + branches: [master-1.15.2, 'feature/**'] pull_request: - branches: [master-1.14.4] + branches: [master-1.15.2] permissions: contents: read concurrency: - group: steamadvantage-1.14-${{ github.workflow }}-${{ github.ref }} + group: steamadvantage-1.15-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: @@ -25,7 +25,7 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/OreSpawn - ref: 9c2488cba02d317e3f31e24441dcc58273d8d0e6 + ref: 5613baf876747ed071cb7ad7e2aff4e0ce4f0a03 path: .ci-dependencies/OreSpawn - name: Use canonical LF dependency inputs # Use the same source bytes on hosted and local dependency builds. @@ -34,14 +34,19 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/BaseMetals - ref: 713802f93f2d1f650e1593fa35c487ea43add4a5 + ref: ac1781e7cade15045ffe0135077087b4d1722603 path: .ci-dependencies/BaseMetals - - name: Check out PowerAdvantage 1.14.4 + - name: Check out PowerAdvantage 1.15.2 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/PowerAdvantage - ref: 1d498ca02b6795b16435f0ece35ac04c67ef6948 + ref: 6666099a734eba16561d98c86f3f4bb1b7c742f7 path: .ci-dependencies/PowerAdvantage + - name: Install pinned Java 25 Mavenizer runtime + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + with: + distribution: temurin + java-version: '25.0.3+9.0.LTS' - name: Install Java 8 toolchain uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: @@ -50,11 +55,18 @@ jobs: - name: Install Java 17 for Gradle uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: - distribution: microsoft - java-version: '17' + distribution: temurin + java-version: '17.0.1+12' + - name: Use pinned build toolchains + # These are Gradle project properties, not JVM system properties. + shell: bash + run: >- + echo "MMD_GRADLE_TOOLCHAINS=-Porg.gradle.java.installations.paths=$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_25_X64 + -Porg.gradle.java.installations.auto-detect=false + -Porg.gradle.java.installations.auto-download=false" >> "$GITHUB_ENV" - name: Set up Gradle uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6 - - name: Build 1.14.4 dependency chain + - name: Build 1.15.2 dependency chain id: dependencies shell: bash run: | @@ -63,14 +75,14 @@ jobs: basemetals="$GITHUB_WORKSPACE/.ci-dependencies/BaseMetals" power="$GITHUB_WORKSPACE/.ci-dependencies/PowerAdvantage" chmod +x "$orespawn/gradlew" "$basemetals/gradlew" "$power/gradlew" - (cd "$orespawn" && ./gradlew jar --no-daemon --stacktrace) - (cd "$basemetals" && ./gradlew jar --no-daemon --stacktrace) - osjar="$orespawn/build/libs-dev/OreSpawn-4.1.1.114041-deobf.jar" - bmjar="$basemetals/build/libs-dev/BaseMetals-3.0.1.114041-deobf.jar" - (cd "$power" && ./gradlew jar verifyReleaseDependencies \ + (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" + (cd "$power" && ./gradlew $MMD_GRADLE_TOOLCHAINS jar verifyReleaseDependencies \ -PbaseMetalsDeobfJar="$bmjar" -PoreSpawnDeobfJar="$osjar" \ --no-daemon --stacktrace) - powerjar="$power/build/libs-dev/PowerAdvantage-2.4.5.114041-deobf.jar" + powerjar="$power/build/libs-dev/PowerAdvantage-2.4.6.115021-deobf.jar" test -f "$osjar" && test -f "$bmjar" && test -f "$powerjar" echo "orespawn=$osjar" >> "$GITHUB_OUTPUT" echo "basemetals=$bmjar" >> "$GITHUB_OUTPUT" @@ -78,7 +90,7 @@ jobs: echo "power_ref=$(git -C "$power" rev-parse HEAD)" >> "$GITHUB_OUTPUT" - name: Build and audit release artifacts run: >- - ./gradlew clean check build javadoc verifyReleaseDependencies verifyReleaseArtifacts + ./gradlew $MMD_GRADLE_TOOLCHAINS clean check build javadoc verifyReleaseDependencies verifyReleaseArtifacts writeReleaseChecksums verifyEclipseProductionClasspath -PpowerAdvantageDeobfJar=${{ steps.dependencies.outputs.power }} -Ppoweradvantage_source_ref=${{ steps.dependencies.outputs.power_ref }} @@ -88,20 +100,20 @@ jobs: - name: Upload audited release candidate uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: SteamAdvantage-1.14.4-${{ github.sha }} + name: SteamAdvantage-1.15.2-${{ github.sha }} if-no-files-found: error retention-days: 30 path: | - build/libs/SteamAdvantage-2.2.6.114041.jar - build/libs/SteamAdvantage-2.2.6.114041-sources.jar - build/libs/SteamAdvantage-2.2.6.114041-javadoc.jar + 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/release/SHA256SUMS CHANGELOG.txt - name: Upload diagnostics on failure if: failure() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: SteamAdvantage-1.14.4-diagnostics-${{ github.sha }} + name: SteamAdvantage-1.15.2-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 9bf204f..7a35df2 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,9 +2,9 @@ name: CodeQL on: push: - branches: [master-1.14.4, 'feature/**'] + branches: [master-1.15.2, 'feature/**'] pull_request: - branches: [master-1.14.4] + branches: [master-1.15.2] schedule: - cron: '53 7 * * 4' @@ -25,7 +25,7 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/OreSpawn - ref: 9c2488cba02d317e3f31e24441dcc58273d8d0e6 + ref: 5613baf876747ed071cb7ad7e2aff4e0ce4f0a03 path: .ci-dependencies/OreSpawn - name: Use canonical LF dependency inputs # Use the same source bytes on hosted and local dependency builds. @@ -34,14 +34,19 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/BaseMetals - ref: 713802f93f2d1f650e1593fa35c487ea43add4a5 + ref: ac1781e7cade15045ffe0135077087b4d1722603 path: .ci-dependencies/BaseMetals - - name: Check out PowerAdvantage 1.14.4 + - name: Check out PowerAdvantage 1.15.2 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: repository: MinecraftModDevelopmentMods/PowerAdvantage - ref: 1d498ca02b6795b16435f0ece35ac04c67ef6948 + ref: 6666099a734eba16561d98c86f3f4bb1b7c742f7 path: .ci-dependencies/PowerAdvantage + - name: Install pinned Java 25 Mavenizer runtime + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + with: + distribution: temurin + java-version: '25.0.3+9.0.LTS' - name: Install Java 8 toolchain uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: @@ -50,11 +55,18 @@ jobs: - name: Install Java 17 for Gradle uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: - distribution: microsoft - java-version: '17' + distribution: temurin + java-version: '17.0.1+12' + - name: Use pinned build toolchains + # These are Gradle project properties, not JVM system properties. + shell: bash + run: >- + echo "MMD_GRADLE_TOOLCHAINS=-Porg.gradle.java.installations.paths=$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_25_X64 + -Porg.gradle.java.installations.auto-detect=false + -Porg.gradle.java.installations.auto-download=false" >> "$GITHUB_ENV" - name: Set up Gradle uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6 - - name: Build 1.14.4 dependency chain + - name: Build 1.15.2 dependency chain id: dependencies shell: bash run: | @@ -63,14 +75,14 @@ jobs: basemetals="$GITHUB_WORKSPACE/.ci-dependencies/BaseMetals" power="$GITHUB_WORKSPACE/.ci-dependencies/PowerAdvantage" chmod +x "$orespawn/gradlew" "$basemetals/gradlew" "$power/gradlew" - (cd "$orespawn" && ./gradlew jar --no-daemon --stacktrace) - (cd "$basemetals" && ./gradlew jar --no-daemon --stacktrace) - osjar="$orespawn/build/libs-dev/OreSpawn-4.1.1.114041-deobf.jar" - bmjar="$basemetals/build/libs-dev/BaseMetals-3.0.1.114041-deobf.jar" - (cd "$power" && ./gradlew jar verifyReleaseDependencies \ + (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" + (cd "$power" && ./gradlew $MMD_GRADLE_TOOLCHAINS jar verifyReleaseDependencies \ -PbaseMetalsDeobfJar="$bmjar" -PoreSpawnDeobfJar="$osjar" \ --no-daemon --stacktrace) - powerjar="$power/build/libs-dev/PowerAdvantage-2.4.5.114041-deobf.jar" + powerjar="$power/build/libs-dev/PowerAdvantage-2.4.6.115021-deobf.jar" test -f "$osjar" && test -f "$bmjar" && test -f "$powerjar" echo "orespawn=$osjar" >> "$GITHUB_OUTPUT" echo "basemetals=$bmjar" >> "$GITHUB_OUTPUT" @@ -83,7 +95,7 @@ jobs: - name: Compile SteamAdvantage production code run: | chmod +x ./gradlew - ./gradlew clean classes --rerun-tasks --no-build-cache --no-daemon --stacktrace \ + ./gradlew $MMD_GRADLE_TOOLCHAINS clean classes --rerun-tasks --no-build-cache --no-daemon --stacktrace \ -PpowerAdvantageDeobfJar=${{ steps.dependencies.outputs.power }} \ -Ppoweradvantage_source_ref=${{ steps.dependencies.outputs.power_ref }} \ -PbaseMetalsDeobfJar=${{ steps.dependencies.outputs.basemetals }} \ diff --git a/.github/workflows/validate-gradle-build.yml b/.github/workflows/validate-gradle-build.yml index c471b09..7d47484 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.14.4 + - master-1.15.2 - 'feature/**' pull_request: branches: - - master-1.14.4 + - master-1.15.2 permissions: contents: read diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 20b90ac..7fc6ea6 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,17 @@ +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. +- Pin the native Power Advantage 2.4.6.115021, Base Metals and OreSpawn development dependencies. +- Use native tile renderer registration, matrix stacks and lit vertex buffers without changing drill dimensions, UVs or animation axes. +- Register the steam track's cutout render layer on the client and retain non-solid helper blocks through native properties. +- Use native entity position accessors and action-result factories for elevators and muskets. +- Preserve registry identities, recipes, migration codecs, saved NBT, machine costs and output quantities. +- Register recipe conditions after parallel setup to prevent intermittent missing recipes at startup. +- Retain the steam track's light transmission and keep tracks and elevator platforms from conducting redstone through their full-cube shapes. +- Add all-facing renderer, lighting, matrix-restoration and native block-property regressions. +- Record combined operating and disposable-copy migration results in Power Advantage's shared 1.15 test notes; manual acceptance remains separate. +- Record the accepted in-game visuals and recipe unlocks; the shared test record retains the remaining limits. + Steam Advantage 2.2.6.114041 - Save the drill's cached facing without reloading a chunk during its unload-save. diff --git a/README.md b/README.md index 095f45d..aca7e9a 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,35 @@ # SteamAdvantage -**Minecraft 1.14.4 port, version 2.2.6.114041.** Native compilation and 27 unit/resource tests pass. -The combined-mod automated checks also cover client resources, connected machinery, -drill movement, chunk lifecycle, restart persistence and disposable-copy migration. -The [1.14 test results](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.14.4/docs/1.14/BROADER-QUALIFICATION.md) -describe the tested scenarios and remaining limits, not a guarantee for an entire modpack. +**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. -Steam Advantage adds steam-powered machines and infrastructure to Power Advantage for Minecraft 1.14.4. +Steam Advantage adds steam-powered machines and infrastructure to Power Advantage for Minecraft 1.15.2. 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. -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. See the 1.14 test results above for this port's coverage. +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. -## Building Minecraft 1.14.4 +## Building Minecraft 1.15.2 -The `master-1.14.4` build targets Forge 28.2.26, snapshot `20190719-1.14.3` mappings, -and MCP `20190829.143755`. It uses ForgeGradle 7.0.34 and Gradle 9.6.1. -Run Gradle with Java 17; production code is compiled for Java 8. +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. -Build the matching 1.14 PowerAdvantage, Base Metals and OreSpawn deobf jars first. +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 1.13 dependency. +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. + With the standard sibling layout: ```text @@ -55,7 +63,7 @@ The Eclipse resource root is `build/resources/main`, so its builder copies expan ## Compatibility -The 1.14 source adaptations preserve machine callbacks, all six drill directions, native +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). @@ -67,8 +75,8 @@ in-world GUI, rendering, sound, control or musket interaction, multiplayer behav or compatibility with arbitrary third-party mods. Unit/resource tests alone are not runtime or world-upgrade evidence. -For an all-Advantage play-test, run `prepareCombinedEclipseLaunch` in the sibling PowerAdvantage checkout and select its `runClientAllAdvantage.launch`. The [native resource probe](https://github.com/MinecraftModDevelopmentMods/PowerAdvantage/blob/master-1.14.4/test-rig/client-resources/README.md) checks models, textures and names across all three mods. These resource checks do not replace gameplay testing. +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; the 1.14 test results above describe this port's coverage. 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. +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. diff --git a/build.gradle b/build.gradle index 23326f7..d6a77c8 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 forge28RunTargets = [client: 'fmluserdevclient', server: 'fmluserdevserver', data: 'fmluserdevdata'] + def forge31RunTargets = [client: 'fmluserdevclient', server: 'fmluserdevserver', data: 'fmluserdevdata'] runs { configureEach { mainClass = 'net.minecraftforge.userdev.LaunchTesting' @@ -102,7 +102,7 @@ minecraft { systemProperty 'forge.logging.markers', 'REGISTRIES' systemProperty 'forge.logging.console.level', 'info' mods { steamadvantage { source sourceSets.main } } - environment 'target', forge28RunTargets[name] + environment 'target', forge31RunTargets[name] environment 'MCP_MAPPINGS', "${mapping_channel}_${mapping_version}" environment 'MCP_VERSION', mcp_version environment 'FORGE_VERSION', forge_version @@ -130,7 +130,7 @@ sourceSets.main.resources { def forgeRunModClassesDirectory = layout.buildDirectory.dir('forge-run-mod-classes/main') def prepareForgeRunModClasses = tasks.register('prepareForgeRunModClasses', Sync) { group = 'ide' - description = 'Merges classes and processed resources for Forge 1.14 launches.' + description = 'Merges classes and processed resources for Forge 1.15 launches.' dependsOn tasks.named('classes') from sourceSets.main.output into forgeRunModClassesDirectory @@ -178,18 +178,18 @@ if (!powerAdvantageDeobfJar.isFile()) { // These defaults follow the sibling MMD checkout layout. They are constants // here so another developer can override them without editing the script. def baseMetalsDeobfJar = file(providers.gradleProperty('baseMetalsDeobfJar') - .getOrElse('../../../../BaseMetals/BaseMetals 114/BaseMetals/build/libs-dev/' - + 'BaseMetals-3.0.1.114041-deobf.jar')) + .getOrElse('../../../../BaseMetals/BaseMetals 115/BaseMetals/build/libs-dev/' + + 'BaseMetals-3.0.2.115021-deobf.jar')) if (!baseMetalsDeobfJar.isFile()) { throw new GradleException("Missing Base Metals deobf jar at ${baseMetalsDeobfJar}. " - + "Build Base Metals 1.14 first, or pass -PbaseMetalsDeobfJar=.") + + "Build Base Metals 1.15 first, or pass -PbaseMetalsDeobfJar=.") } def oreSpawnDeobfJar = file(providers.gradleProperty('oreSpawnDeobfJar') - .getOrElse('../../../../MinecraftMineralogy/OS114/OreSpawn/build/libs-dev/' - + 'OreSpawn-4.1.1.114041-deobf.jar')) + .getOrElse('../../../../MinecraftMineralogy/OS115/OreSpawn/build/libs-dev/' + + 'OreSpawn-4.1.1.115021-deobf.jar')) if (!oreSpawnDeobfJar.isFile()) { throw new GradleException("Missing OreSpawn deobf jar at ${oreSpawnDeobfJar}. " - + "Build OreSpawn 1.14 first, or pass -PoreSpawnDeobfJar=.") + + "Build OreSpawn 1.15 first, or pass -PoreSpawnDeobfJar=.") } dependencies { @@ -341,14 +341,17 @@ tasks.register('verifyReleaseConfiguration') { group = 'verification' description = 'Validates release identity, target metadata, and dependency policy.' doLast { - if (project.mod_version != '2.2.6.114041') { + 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 (project.mod_version != '2.2.7.115021') { throw new GradleException("Unexpected SteamAdvantage release version: ${project.mod_version}") } - if (project.minecraft_version != '1.14.4' - || project.forge_version != '28.2.26' + if (project.minecraft_version != '1.15.2' + || project.forge_version != '31.2.57' || project.mapping_channel != 'snapshot' - || project.mapping_version != '20190719-1.14.3' - || project.mcp_version != '20190829.143755') { + || project.mapping_version != '20200514-1.15.1' + || project.mcp_version != '20200515.085601') { throw new GradleException('Unexpected Minecraft, Forge, or mappings target') } if (project.loader_name != 'forge' || project.loader_code != '1' @@ -366,10 +369,10 @@ tasks.register('verifyReleaseConfiguration') { } if (project.cf_requirements != 'power-advantage,base-metals' || project.cf_optionals != '' - || project.cf_versions != '1.14.4') { + || project.cf_versions != '1.15.2') { throw new GradleException('Unexpected CurseForge dependency or game-version metadata') } - if (project.poweradvantage_version != '2.4.5.114041' + if (project.poweradvantage_version != '2.4.6.115021' || project.poweradvantage_source_repository != 'MinecraftModDevelopmentMods/PowerAdvantage' || !(project.poweradvantage_source_ref ==~ /[a-f0-9]{40}/) || !(project.poweradvantage_deobf_sha256 ==~ /[A-F0-9]{64}/)) { @@ -378,12 +381,12 @@ tasks.register('verifyReleaseConfiguration') { 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.6.114041"')) { + || !mainSource.contains('VERSION = "2.2.7.115021"')) { 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.5.114041,3.0.0)"'].each { marker -> + 'versionRange="[2.4.6.115021,3.0.0)"'].each { marker -> if (!metadata.contains(marker)) { throw new GradleException("Source mods.toml is missing ${marker}") } @@ -419,9 +422,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.14.4-28.2.26' + if (manifest.getValue('Built-On') != '1.15.2-31.2.57' || manifest.getValue('Built-On-Java') != '8') { - throw new GradleException('PowerAdvantage must be the native 1.14.4 Java 8 dependency') + throw new GradleException('PowerAdvantage must be the native 1.15.2 Java 8 dependency') } } String actualBaseMetalsHash = MessageDigest.getInstance('SHA-256') @@ -522,8 +525,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 != 4) { - throw new GradleException('Packaged resources must use native 1.14 pack format 4') + if (resourcePack.pack.pack_format != 5) { + throw new GradleException('Packaged resources must use native 1.15 pack format 5') } ['agent-notes/', '.codex/', 'src/test/', 'fernflower_abstract_parameter_names.txt', 'cyano/poweradvantage/', diff --git a/gradle.properties b/gradle.properties index fd46c88..f28d4e6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,14 +5,14 @@ org.gradle.caching=true org.gradle.parallel=false net.minecraftforge.gradle.merge-source-sets=false -minecraft_version=1.14.4 -minecraft_version_range=[1.14.4] -forge_version=28.2.26 -forge_version_range=[28,) -loader_version_range=[28,) +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=20190719-1.14.3 -mcp_version=20190829.143755 +mapping_version=20200514-1.15.1 +mcp_version=20200515.085601 loader_name=forge loader_code=1 @@ -25,23 +25,23 @@ curseforge_project_id=240984 mod_id=steamadvantage mod_name=Steam Advantage mod_license=GPL-3.0-only -mod_version=2.2.6.114041 +mod_version=2.2.7.115021 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.14.4 +cf_versions=1.15.2 -poweradvantage_version=2.4.5.114041 +poweradvantage_version=2.4.6.115021 poweradvantage_source_repository=MinecraftModDevelopmentMods/PowerAdvantage # Exact Power Advantage source and development jar used by local and CI builds. -poweradvantage_source_ref=1d498ca02b6795b16435f0ece35ac04c67ef6948 -poweradvantage_deobf_sha256=8D8831D54B700FBFB2B9C43EE3D8D70D2B7E57185A4DBDF12202C47D5E387B39 +poweradvantage_source_ref=6666099a734eba16561d98c86f3f4bb1b7c742f7 +poweradvantage_deobf_sha256=F5029356CB837E7D782BA59D4C3B961CE0AAA116B739F14DA63F0A13562A2D1F -basemetals_version=3.0.1.114041 -basemetals_deobf_sha256=A14A87E3BF30964F901E715A9B4EF2F1E7317ABE7F9ACEBE60D8E6A900CA6EB2 +basemetals_version=3.0.2.115021 +basemetals_deobf_sha256=426FE639C97E1DE4F6624957E3CBDE68A5FB7D415A1047903A29DCB35FD9ADA2 -orespawn_version=4.1.1.114041 -orespawn_deobf_sha256=1807C3A43F6E854F4EC5741F75A52750B733CD81DC588CF0F666C6C3A489FBEF +orespawn_version=4.1.1.115021 +orespawn_deobf_sha256=358B13375A4B60622C491D6729290971A446FF14D524A600CA13710934DB3FDC diff --git a/gradlew.bat b/gradlew.bat index e95643d..f955316 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,84 +1,84 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/zone/moddev/mc/steamadvantage/SteamAdvantage.java b/src/main/java/zone/moddev/mc/steamadvantage/SteamAdvantage.java index c2aad97..3bbbe8e 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.14 entry point for Steam Advantage. */ +/** Forge 1.15 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.6.114041"; + public static final String VERSION = "2.2.7.115021"; public static final Logger LOGGER = LogManager.getLogger(MODID); public static float MUSKET_DAMAGE = 20.0F; @@ -50,7 +50,6 @@ public SteamAdvantage() { Entities.init(); Enchantments.init(); GUI.init(); - RecipeConditions.register(); migrateLegacyConfiguration(); ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, SteamAdvantageConfig.SPEC); @@ -80,6 +79,8 @@ 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); 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 03558dd..aa2b6d7 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/blocks/DrillBitBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/blocks/DrillBitBlock.java @@ -25,14 +25,12 @@ 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); public DrillBitBlock() { - super(Block.Properties.create(Material.IRON).hardnessAndResistance(5.0F, 2000.0F)); + super(Block.Properties.create(Material.IRON).hardnessAndResistance(5.0F, 2000.0F).notSolid()); } @Override public TileEntity createNewTileEntity(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 boolean isNormalCube(BlockState state, IBlockReader world, BlockPos pos) { return false; } - @Override public boolean isSolid(BlockState state) { return false; } @Override public List getDrops(BlockState state, LootContext.Builder context) { return Collections.emptyList(); } @Override 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 ff9349b..07c7add 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/blocks/PlatformBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/blocks/PlatformBlock.java @@ -29,7 +29,7 @@ public class PlatformBlock extends Block { }; public PlatformBlock() { - super(Block.Properties.create(Material.IRON).hardnessAndResistance(5.0F, 2000.0F)); + super(Block.Properties.create(Material.IRON).hardnessAndResistance(5.0F, 2000.0F).notSolid()); setDefaultState(getStateContainer().getBaseState().with(HEIGHT, 1)); } @@ -37,7 +37,6 @@ public PlatformBlock() { @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 public boolean isSolid(BlockState state) { return false; } @Override public List getDrops(BlockState state, LootContext.Builder context) { return Collections.emptyList(); } @Override 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 496eb22..3a0fb9f 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/blocks/PumpPipeBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/blocks/PumpPipeBlock.java @@ -20,13 +20,11 @@ public class PumpPipeBlock extends Block { private static final VoxelShape SHAPE = VoxelShapes.create(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)); + super(Block.Properties.create(Material.IRON).hardnessAndResistance(5.0F, 10.0F).notSolid()); } @Override public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) { return SHAPE; } @Override public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) { return SHAPE; } - @Override public boolean isNormalCube(BlockState state, IBlockReader world, BlockPos pos) { return false; } - @Override public boolean isSolid(BlockState state) { return false; } @Override public List getDrops(BlockState state, LootContext.Builder context) { return Collections.emptyList(); } @Override 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 a3cca5b..7a3ff6b 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/blocks/SteamTrackBlock.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/blocks/SteamTrackBlock.java @@ -3,21 +3,19 @@ import cyano.poweradvantage.api.simple.BlockSimplePowerConduit; import net.minecraft.block.material.Material; import net.minecraft.block.BlockState; -import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.math.BlockPos; 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.IBlockReader; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import zone.moddev.mc.steamadvantage.init.Power; public class SteamTrackBlock extends BlockSimplePowerConduit { - public SteamTrackBlock() { super(Material.PISTON, 0.75F, 2.0F / 16.0F, Power.steam_power); } + public SteamTrackBlock() { + super(Properties.create(Material.PISTON).hardnessAndResistance(0.75F).notSolid(), + 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 boolean isSolid(BlockState state) { return false; } - @OnlyIn(Dist.CLIENT) @Override public BlockRenderLayer getRenderLayer() { return BlockRenderLayer.CUTOUT; } } 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 2ac4591..1f43107 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/graphics/ClientRegistration.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/graphics/ClientRegistration.java @@ -2,13 +2,17 @@ import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -import zone.moddev.mc.steamadvantage.blocks.DrillBitTileEntity; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.RenderTypeLookup; +import zone.moddev.mc.steamadvantage.init.Blocks; +import zone.moddev.mc.steamadvantage.init.Entities; /** Client-only renderer registration. */ public final class ClientRegistration { private ClientRegistration() {} public static void onClientSetup(FMLClientSetupEvent event) { - ClientRegistry.bindTileEntitySpecialRenderer(DrillBitTileEntity.class, new DrillBitRenderer()); + ClientRegistry.bindTileEntityRenderer(Entities.DRILLBIT, DrillBitRenderer::new); + RenderTypeLookup.setRenderLayer(Blocks.steam_track, RenderType.getCutout()); } } 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 6a95cee..5024790 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/graphics/DrillBitRenderer.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/graphics/DrillBitRenderer.java @@ -1,121 +1,87 @@ package zone.moddev.mc.steamadvantage.graphics; -import zone.moddev.mc.steamadvantage.SteamAdvantage; -import zone.moddev.mc.steamadvantage.blocks.DrillBitTileEntity; -import net.minecraft.client.Minecraft; -import com.mojang.blaze3d.platform.GlStateManager; -import net.minecraft.client.renderer.RenderHelper; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.BufferBuilder; +import com.mojang.blaze3d.matrix.MatrixStack; +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.client.renderer.tileentity.TileEntityRenderer; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import zone.moddev.mc.steamadvantage.SteamAdvantage; +import zone.moddev.mc.steamadvantage.blocks.DrillBitTileEntity; -@OnlyIn(Dist.CLIENT) // This is needed for classes that extend client-only classes -public class DrillBitRenderer extends TileEntityRenderer{ - - - private final ResourceLocation texture = new ResourceLocation(SteamAdvantage.MODID+":textures/entity/drill_bit.png"); - - public DrillBitRenderer() { - } - - - @Override - public void render(final DrillBitTileEntity te, final double x, final double y, final double z, final float partialTick, final int destroyStage) { - GlStateManager.pushMatrix(); - try { - GlStateManager.translated(x, y, z); - render(te,te.getWorld(),te.getPos(),partialTick); - } finally { - GlStateManager.enableCull(); - GlStateManager.disableBlend(); - GlStateManager.shadeModel(7424); - RenderHelper.enableStandardItemLighting(); - GlStateManager.popMatrix(); - } - } - - private void render(DrillBitTileEntity e, World world, BlockPos pos, float partialTick){ - final Tessellator instance = Tessellator.getInstance(); - final BufferBuilder worldRenderer = instance.getBuffer(); - - this.bindTexture(texture); - - //This will make your block brightness dependent from surroundings lighting. - RenderHelper.disableStandardItemLighting(); - GlStateManager.blendFunc(770, 771); - GlStateManager.enableBlend(); - GlStateManager.disableCull(); - - if (Minecraft.isAmbientOcclusionEnabled()) - { - GlStateManager.shadeModel(7425); +@OnlyIn(Dist.CLIENT) +public class DrillBitRenderer extends TileEntityRenderer { + private static final ResourceLocation TEXTURE = + new ResourceLocation(SteamAdvantage.MODID, "textures/entity/drill_bit.png"); + + public DrillBitRenderer(TileEntityRendererDispatcher dispatcher) { + super(dispatcher); + } + + @Override + 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); + } + + static void renderGeometry(Direction.Axis axis, float rotation, MatrixStack matrices, + IVertexBuilder vertices, int light, int overlay) { + matrices.push(); + 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.rotate(Vector3f.YP.rotationDegrees(rotation)); + MatrixStack.Entry transform = matrices.getLast(); + 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); + vertex(transform, vertices, radius, -0.5F, -radius, 0, 1, 0, 0, -1, light, overlay); + vertex(transform, vertices, -radius, -0.5F, -radius, 0.5F, 1, 0, 0, -1, light, overlay); + vertex(transform, vertices, -radius, 0.5F, -radius, 0.5F, 0, 0, 0, -1, light, overlay); + + vertex(transform, vertices, -radius, 0.5F, radius, 0, 0, 0, 0, 1, light, overlay); + vertex(transform, vertices, -radius, -0.5F, radius, 0, 1, 0, 0, 1, light, overlay); + vertex(transform, vertices, radius, -0.5F, radius, 0.5F, 1, 0, 0, 1, light, overlay); + vertex(transform, vertices, radius, 0.5F, radius, 0.5F, 0, 0, 0, 1, light, overlay); + + vertex(transform, vertices, -radius, 0.5F, -radius, 0, 0, -1, 0, 0, light, overlay); + vertex(transform, vertices, -radius, -0.5F, -radius, 0, 1, -1, 0, 0, light, overlay); + vertex(transform, vertices, -radius, -0.5F, radius, 0.5F, 1, -1, 0, 0, light, overlay); + vertex(transform, vertices, -radius, 0.5F, radius, 0.5F, 0, -1, 0, 0, light, overlay); + + vertex(transform, vertices, radius, 0.5F, radius, 0, 0, 1, 0, 0, light, overlay); + vertex(transform, vertices, radius, -0.5F, radius, 0, 1, 1, 0, 0, light, overlay); + vertex(transform, vertices, radius, -0.5F, -radius, 0.5F, 1, 1, 0, 0, light, overlay); + vertex(transform, vertices, radius, 0.5F, -radius, 0.5F, 0, 1, 0, 0, light, overlay); + + vertex(transform, vertices, -radius, 0.5F, -radius, 0.5F, 0, 0, 1, 0, light, overlay); + vertex(transform, vertices, -radius, 0.5F, radius, 0.5F, 0.5F, 0, 1, 0, light, overlay); + 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); + + vertex(transform, vertices, -radius, -0.5F, radius, 0.5F, 0, 0, -1, 0, light, overlay); + vertex(transform, vertices, -radius, -0.5F, -radius, 0.5F, 0.5F, 0, -1, 0, light, overlay); + 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(); } - else - { - GlStateManager.shadeModel(7424); - } - - final float sideU0 = 0; - final float sideU1 = 0.5f; - final float sideV0 = 0; - final float sideV1 = 1f; - final float endU0 = 0.5f; - final float endU1 = 1; - final float endV0 = 0; - final float endV1 = 0.5f; - final float radius = 0.25f; - - GlStateManager.translatef(0.5f, 0.5f, 0.5f); - if(e.getDirection() != Direction.Axis.Y){ - GlStateManager.rotatef(90, 1.0f, 0.0f, 0.0f); - if(e.getDirection() != Direction.Axis.Z){ - GlStateManager.rotatef(90, 0.0f, 0.0f, 1.0f); - } - } - GlStateManager.rotatef(e.rotation + DrillBitTileEntity.ROTATION_PER_TICK * partialTick, 0.0f, 1.0f, 0.0f); - - worldRenderer.begin(7, DefaultVertexFormats.POSITION_TEX); - worldRenderer.pos( radius, 0.5f, -radius).tex( sideU0, sideV0).endVertex(); - worldRenderer.pos( radius,-0.5f, -radius).tex( sideU0, sideV1).endVertex(); - worldRenderer.pos(-radius,-0.5f, -radius).tex( sideU1, sideV1).endVertex(); - worldRenderer.pos(-radius, 0.5f, -radius).tex( sideU1, sideV0).endVertex(); - - worldRenderer.pos(-radius, 0.5f, radius).tex( sideU0, sideV0).endVertex(); - worldRenderer.pos(-radius,-0.5f, radius).tex( sideU0, sideV1).endVertex(); - worldRenderer.pos( radius,-0.5f, radius).tex( sideU1, sideV1).endVertex(); - worldRenderer.pos( radius, 0.5f, radius).tex( sideU1, sideV0).endVertex(); - - worldRenderer.pos(-radius, 0.5f, -radius).tex( sideU0, sideV0).endVertex(); - worldRenderer.pos(-radius,-0.5f, -radius).tex( sideU0, sideV1).endVertex(); - worldRenderer.pos(-radius,-0.5f, radius).tex( sideU1, sideV1).endVertex(); - worldRenderer.pos(-radius, 0.5f, radius).tex( sideU1, sideV0).endVertex(); - - worldRenderer.pos( radius, 0.5f, radius).tex( sideU0, sideV0).endVertex(); - worldRenderer.pos( radius,-0.5f, radius).tex( sideU0, sideV1).endVertex(); - worldRenderer.pos( radius,-0.5f, -radius).tex( sideU1, sideV1).endVertex(); - worldRenderer.pos( radius, 0.5f, -radius).tex( sideU1, sideV0).endVertex(); - - worldRenderer.pos(-radius, 0.5f, -radius).tex( endU0, endV0).endVertex(); - worldRenderer.pos(-radius, 0.5f, radius).tex( endU0, endV1).endVertex(); - worldRenderer.pos( radius, 0.5f, radius).tex( endU1, endV1).endVertex(); - worldRenderer.pos( radius, 0.5f, -radius).tex( endU1, endV0).endVertex(); - - worldRenderer.pos(-radius,-0.5f, radius).tex( endU0, endV0).endVertex(); - worldRenderer.pos(-radius,-0.5f, -radius).tex( endU0, endV1).endVertex(); - worldRenderer.pos( radius,-0.5f, -radius).tex( endU1, endV1).endVertex(); - worldRenderer.pos( radius,-0.5f, radius).tex( endU1, endV0).endVertex(); - - instance.draw(); - RenderHelper.enableStandardItemLighting(); - - } - - + } + + 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(); + } } 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 7d437c8..69d44da 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/items/MusketItem.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/items/MusketItem.java @@ -32,7 +32,6 @@ import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.play.server.SEntityVelocityPacket; import net.minecraft.util.ActionResult; -import net.minecraft.util.ActionResultType; import net.minecraft.util.Hand; import net.minecraft.particles.IParticleData; import net.minecraft.util.ResourceLocation; @@ -113,18 +112,18 @@ 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.newResult(ActionResultType.PASS,srcItemStack); - if(!hasAmmo(playerEntity, srcItemStack)) return ActionResult.newResult(ActionResultType.FAIL,srcItemStack); + 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){ // instant reload decrementAmmo(playerEntity,srcItemStack); startLoad(srcItemStack); playSound(SoundEvents.BLOCK_LEVER_CLICK,world,playerEntity); finishLoad(srcItemStack); - return ActionResult.newResult(ActionResultType.SUCCESS,srcItemStack); + return ActionResult.resultSuccess(srcItemStack); } playerEntity.setActiveHand(hand); - return ActionResult.newResult(ActionResultType.SUCCESS,srcItemStack); + return ActionResult.resultSuccess(srcItemStack); } @Override @@ -167,15 +166,15 @@ protected void fire(ItemStack srcItemStack, LivingEntity playerEntity, } Vec3d lookVector = playerEntity.getLookVec(); spawnParticle(ParticleTypes.EXPLOSION_EMITTER, world, - playerEntity.posX+lookVector.x, playerEntity.posY+playerEntity.getEyeHeight()+lookVector.y, playerEntity.posZ + lookVector.z); + playerEntity.getPosX()+lookVector.x, playerEntity.getPosY()+playerEntity.getEyeHeight()+lookVector.y, playerEntity.getPosZ() + lookVector.z); if(world.isRemote){ playerEntity.rotationPitch -= 15; return; } playSound(SoundEvents.ITEM_FLINTANDSTEEL_USE,world,playerEntity); - playBigSoundAtPosition(playerEntity.posX,playerEntity.posY,playerEntity.posZ, SoundEvents.ENTITY_FIREWORK_ROCKET_BLAST,SoundCategory.PLAYERS,2F,0.5F,world); + playBigSoundAtPosition(playerEntity.getPosX(),playerEntity.getPosY(),playerEntity.getPosZ(), SoundEvents.ENTITY_FIREWORK_ROCKET_BLAST,SoundCategory.PLAYERS,2F,0.5F,world); - Vec3d start = new Vec3d(playerEntity.posX, playerEntity.posY+playerEntity.getEyeHeight(),playerEntity.posZ); + Vec3d start = new Vec3d(playerEntity.getPosX(), playerEntity.getPosY()+playerEntity.getEyeHeight(),playerEntity.getPosZ()); start.add(MAX_RANGE * lookVector.x, MAX_RANGE * lookVector.y, MAX_RANGE * lookVector.z); RayTraceResult rayTrace = rayTraceBlocksAndEntities(world,MAX_RANGE,playerEntity); if(rayTrace == null){ @@ -188,11 +187,11 @@ protected void fire(ItemStack srcItemStack, LivingEntity playerEntity, 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.posX, e.posY+0.5, e.posZ, + world.createExplosion(playerEntity, e.getPosX(), e.getPosY()+0.5, e.getPosZ(), explodeFactor * lvl, Explosion.Mode.BREAK); - AxisAlignedBB fireArea = new AxisAlignedBB(e.posX-lvl, e.posY-lvl, e.posZ-lvl, - e.posX+lvl, e.posY+lvl, e.posZ+lvl); + 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); for(LivingEntity victim : collateralDamage){ victim.setFire(lvl); @@ -274,7 +273,7 @@ public boolean hitEntity(ItemStack stack, LivingEntity target, LivingEntity atta protected void playSound(SoundEvent sound, World world, Entity e){ if (!world.isRemote) { - playSoundAtPosition(e.posX, e.posY, e.posZ, sound,SoundCategory.PLAYERS,1F,1F,world); + playSoundAtPosition(e.getPosX(), e.getPosY(), e.getPosZ(), sound,SoundCategory.PLAYERS,1F,1F,world); } } @@ -368,7 +367,7 @@ 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.posX, source.posY + source.getEyeHeight(), source.posZ); + Vec3d rayOrigin = new Vec3d(source.getPosX(), source.getPosY() + source.getEyeHeight(), source.getPosZ()); Vec3d rayDirection = source.getLookVec(); BlockPos srcPos = source.getPosition(); AxisAlignedBB aoi = new AxisAlignedBB(srcPos.getX() - maxRange, srcPos.getY() - maxRange, srcPos.getZ() - maxRange, @@ -377,7 +376,7 @@ public static RayTraceResult rayTraceBlocksAndEntities(World w, double maxRange, double closestDistSqr = Double.MAX_VALUE; Entity closestEntity = null; for(Entity e : entities){ - double distSqr = e.getDistanceSq(source.posX, source.posY, source.posZ); + double distSqr = e.getDistanceSq(source.getPosX(), source.getPosY(), source.getPosZ()); if(distSqr < rangeSqr){ // e is within range AxisAlignedBB box = e.getBoundingBox(); @@ -395,7 +394,7 @@ public static RayTraceResult rayTraceBlocksAndEntities(World w, double maxRange, return w.rayTraceBlocks(new RayTraceContext(rayOrigin, rayOrigin.add(mul(rayDirection, maxRange)), RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.SOURCE_ONLY, source)); } else { - Vec3d pos = new Vec3d(closestEntity.posX, closestEntity.posY+closestEntity.getEyeHeight(), closestEntity.posZ); + Vec3d pos = new Vec3d(closestEntity.getPosX(), closestEntity.getPosY()+closestEntity.getEyeHeight(), closestEntity.getPosZ()); RayTraceResult entityCollision = new EntityRayTraceResult(closestEntity, pos); return entityCollision; } 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 3390870..8f57751 100644 --- a/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamElevatorTileEntity.java +++ b/src/main/java/zone/moddev/mc/steamadvantage/machines/SteamElevatorTileEntity.java @@ -79,7 +79,7 @@ private boolean moveUp(){ getPos().getX()+1, topPos.getY(), getPos().getZ()+1)); for(Entity e : passengers){ - e.setPositionAndUpdate(e.posX,topPos.getY()+smallAmount, e.posZ); + e.setPositionAndUpdate(e.getPosX(),topPos.getY()+smallAmount, e.getPosZ()); e.fallDistance = 0; } return true; @@ -106,7 +106,7 @@ private boolean moveDown(){ new AxisAlignedBB(p.getX(),p.getY(),p.getZ(), p.getX()+1, p.getY()+2, p.getZ()+1)); for(Entity e : passengers){ - e.setPositionAndUpdate(e.posX, destination.getY()+smallAmount,e.posZ); + e.setPositionAndUpdate(e.getPosX(), destination.getY()+smallAmount,e.getPosZ()); e.fallDistance = 0; } return true; diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 4aee25d..2ee02b0 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.5.114041,3.0.0)" +versionRange="[2.4.6.115021,3.0.0)" ordering="AFTER" side="BOTH" [[dependencies.steamadvantage]] modId="basemetals" mandatory=false -versionRange="[3.0.1.114041,4.0.0)" +versionRange="[3.0.1.115021,4.0.0)" ordering="AFTER" side="BOTH" diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index 8be9850..e8e4d16 100644 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -1,6 +1,6 @@ { "pack":{ - "pack_format":4, + "pack_format":5, "description":"Steam Advantage" } } diff --git a/src/test/java/zone/moddev/mc/steamadvantage/graphics/DrillBitRendererTest.java b/src/test/java/zone/moddev/mc/steamadvantage/graphics/DrillBitRendererTest.java new file mode 100644 index 0000000..d4d0be4 --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/graphics/DrillBitRendererTest.java @@ -0,0 +1,103 @@ +package zone.moddev.mc.steamadvantage.graphics; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.vertex.IVertexBuilder; +import java.util.ArrayList; +import java.util.List; +import net.minecraft.util.Direction; +import org.junit.Test; +import static org.junit.Assert.*; + +public class DrillBitRendererTest { + private static final int LIGHT = 0x00D000A0; + private static final int OVERLAY = 0x00090007; + private static final double EPSILON = 0.000001D; + + @Test public void everyFacingKeepsLegacyDimensionsUvsAndNativeVertexAttributes() { + for (Direction facing : Direction.values()) { + RecordingBuffer buffer = new RecordingBuffer(); + MatrixStack matrices = new MatrixStack(); + MatrixStack.Entry caller = matrices.getLast(); + DrillBitRenderer.renderGeometry(facing.getAxis(), 0, matrices, buffer, LIGHT, OVERLAY); + assertSame(caller, matrices.getLast()); + 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 }; + for (int i = 0; i < buffer.vertices.size(); i++) { + Vertex vertex = buffer.vertices.get(i); + for (int coordinate = 0; coordinate < 3; coordinate++) { + minimum[coordinate] = Math.min(minimum[coordinate], vertex.position[coordinate]); + maximum[coordinate] = Math.max(maximum[coordinate], vertex.position[coordinate]); + } + int corner = i % 4; + float expectedU = (i < 16 ? 0 : 0.5F) + (corner >= 2 ? 0.5F : 0); + float expectedV = (corner == 1 || corner == 2) ? (i < 16 ? 1 : 0.5F) : 0; + assertEquals(expectedU, vertex.u, 0); + assertEquals(expectedV, vertex.v, 0); + assertEquals(LIGHT, vertex.light); + assertEquals(OVERLAY, vertex.overlay); + assertArrayEquals(new int[] { 255, 255, 255, 255 }, vertex.color); + double normalLength = 0; + for (float component : vertex.normal) normalLength += component * component; + assertEquals(1, normalLength, EPSILON); + } + for (int coordinate = 0; coordinate < 3; coordinate++) { + boolean alongDrill = Direction.Axis.values()[coordinate] == facing.getAxis(); + assertEquals(alongDrill ? 0 : 0.25D, minimum[coordinate], EPSILON); + assertEquals(alongDrill ? 1 : 0.75D, maximum[coordinate], EPSILON); + } + } + } + + @Test public void rotationTransformsBothPositionsAndNormals() { + RecordingBuffer buffer = new RecordingBuffer(); + DrillBitRenderer.renderGeometry(Direction.Axis.Y, 90, new MatrixStack(), buffer, LIGHT, OVERLAY); + Vertex first = buffer.vertices.get(0); + assertArrayEquals(new double[] { 0.25D, 1, 0.25D }, first.position, EPSILON); + assertArrayEquals(new float[] { -1, 0, 0 }, first.normal, (float) EPSILON); + } + + @Test public void failedVertexSubmissionRestoresTheCallerMatrix() { + MatrixStack matrices = new MatrixStack(); + MatrixStack.Entry caller = matrices.getLast(); + try { + DrillBitRenderer.renderGeometry(Direction.Axis.X, 37, matrices, new RecordingBuffer() { + @Override public void endVertex() { throw new IllegalStateException("submission failed"); } + }, LIGHT, OVERLAY); + fail("Expected vertex submission failure"); + } catch (IllegalStateException expected) { + assertEquals("submission failed", expected.getMessage()); + } + assertSame(caller, matrices.getLast()); + } + + private static final class Vertex { + final double[] position = new double[3]; + final int[] color = new int[4]; + final float[] normal = new float[3]; + float u, v; + int overlay, light; + } + + 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) { + vertex.position[0] = x; vertex.position[1] = y; vertex.position[2] = z; + return this; + } + @Override public IVertexBuilder color(int red, int green, int blue, int alpha) { + 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 normal(float x, float y, float z) { + vertex.normal[0] = x; vertex.normal[1] = y; vertex.normal[2] = z; + return this; + } + @Override public void endVertex() { vertices.add(vertex); vertex = new Vertex(); } + } +} diff --git a/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java new file mode 100644 index 0000000..6a0863a --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/resources/BuildWorkflowContractTest.java @@ -0,0 +1,28 @@ +package zone.moddev.mc.steamadvantage.resources; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import org.junit.Test; +import static org.junit.Assert.*; + +public class BuildWorkflowContractTest { + @Test public void everyHostedBuildUsesPinnedToolchainProjectProperties() throws Exception { + 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("-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")); + assertFalse(name, source.contains("-Dorg.gradle.java.installations.")); + for (String line : source.split("\\R")) { + if (line.contains("./gradlew ") && !line.contains("chmod")) { + assertTrue(name + ": " + line, line.contains("./gradlew $MMD_GRADLE_TOOLCHAINS ")); + } + } + } + } +} diff --git a/src/test/java/zone/moddev/mc/steamadvantage/resources/NativeBlockPropertiesTest.java b/src/test/java/zone/moddev/mc/steamadvantage/resources/NativeBlockPropertiesTest.java new file mode 100644 index 0000000..903f882 --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/resources/NativeBlockPropertiesTest.java @@ -0,0 +1,95 @@ +package zone.moddev.mc.steamadvantage.resources; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.shapes.IBooleanFunction; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.util.math.shapes.VoxelShapes; +import net.minecraft.util.registry.Bootstrap; +import net.minecraft.world.EmptyBlockReader; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import zone.moddev.mc.steamadvantage.blocks.PlatformBlock; +import zone.moddev.mc.steamadvantage.blocks.SteamTrackBlock; +import static org.junit.Assert.*; + +@RunWith(Parameterized.class) +public class NativeBlockPropertiesTest { + @Parameterized.Parameters(name = "{0}") + public static Collection cases() { + return Arrays.asList(new Object[][] { + {"steam_track", -1}, {"platform_height_0", 0}, {"platform_height_1", 1}, + {"platform_height_2", 2}, {"platform_height_3", 3}, {"platform_height_4", 4} + }); + } + + @Parameterized.Parameter public String name; + @Parameterized.Parameter(1) public int height; + private Block block; + + @BeforeClass public static void bootstrapNativeRegistries() { Bootstrap.register(); } + + @Before public void createNativeBlockAndStateCaches() { + block = height < 0 ? new SteamTrackBlock() : new PlatformBlock(); + for (BlockState state : block.getStateContainer().getValidStates()) state.cacheState(); + } + + @Test public void remainsNonSolid() { + for (BlockState state : states()) assertFalse(state.toString(), state.isSolid()); + } + + @Test public void remainsNonOpaque() { + for (BlockState state : states()) { + assertFalse(state.toString(), state.isOpaqueCube(EmptyBlockReader.INSTANCE, BlockPos.ZERO)); + } + } + + @Test public void retainsNativeOpacityForTheLegacyShape() { + // 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)); + } + } + + @Test public void remainsANonNormalCube() { + for (BlockState state : states()) { + assertFalse(state.toString(), state.isNormalCube(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. + assertFalse(state + " face=" + face, state.shouldCheckWeakPower(null, BlockPos.ZERO, face)); + } + } + } + + @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); + if (height < 0) assertEquals(64, states().size()); + for (BlockState state : states()) { + assertFalse(state + " outline", VoxelShapes.compare(expected, + state.getShape(EmptyBlockReader.INSTANCE, BlockPos.ZERO), IBooleanFunction.NOT_SAME)); + assertFalse(state + " collision", VoxelShapes.compare(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)); + } +} 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 b320881..6dae7f5 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 packUsesNative114Format() throws Exception { - assertEquals(4, read(ROOT.resolve("pack.mcmeta")).getAsJsonObject("pack").get("pack_format").getAsInt()); + @Test public void packUsesNative115Format() throws Exception { + assertEquals(5, 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 new file mode 100644 index 0000000..e900e10 --- /dev/null +++ b/src/test/java/zone/moddev/mc/steamadvantage/resources/RecipeRegistrationThreadTest.java @@ -0,0 +1,49 @@ +package zone.moddev.mc.steamadvantage.resources; + +import java.io.InputStream; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.Handle; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import static org.junit.Assert.*; + +public class RecipeRegistrationThreadTest { + @Test public void sharedForgeConditionsAreRegisteredAfterParallelSetup() throws Exception { + ClassNode node = new ClassNode(); + try (InputStream input = getClass().getResourceAsStream("/zone/moddev/mc/steamadvantage/SteamAdvantage.class")) { + assertNotNull(input); + new ClassReader(input).accept(node, 0); + } + String conditions = "zone/moddev/mc/steamadvantage/recipe/RecipeConditions"; + int queued = 0; + for (MethodNode method : node.methods) { + boolean registrationRunnable = false; + for (AbstractInsnNode instruction : method.instructions.toArray()) { + if (instruction instanceof MethodInsnNode) { + 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) { + assertEquals("Register conditions during common setup", "commonSetup", method.name); + queued++; + registrationRunnable = false; + } + } + if (instruction instanceof InvokeDynamicInsnNode) { + for (Object argument : ((InvokeDynamicInsnNode) instruction).bsmArgs) { + if (argument instanceof Handle && ((Handle) argument).getOwner().equals(conditions) + && ((Handle) argument).getName().equals("register")) { + registrationRunnable = true; + } + } + } + } + } + assertEquals("Queue registration exactly once on Forge's loading thread", 1, queued); + } +}