diff --git a/.github/verify-published-pins.sh b/.github/verify-published-pins.sh index 191e14a5..40fb118f 100644 --- a/.github/verify-published-pins.sh +++ b/.github/verify-published-pins.sh @@ -18,10 +18,10 @@ done require_merged() { local repo="$1" ref="$2" status [[ "$ref" =~ ^[a-f0-9]{40}$ ]] - status="$(gh api "repos/MinecraftModDevelopmentMods/$repo/compare/$ref...master-1.21.1" --jq '.status')" + status="$(gh api "repos/MinecraftModDevelopmentMods/$repo/compare/$ref...master-1.21.11" --jq '.status')" case "$status" in identical|ahead) ;; - *) echo "::error::$repo $ref is not on upstream master-1.21.1 ($status)."; exit 1 ;; + *) echo "::error::$repo $ref is not on upstream master-1.21.11 ($status)."; exit 1 ;; esac } @@ -48,7 +48,7 @@ require_merged basePower "$power_ref" require_merged BaseMetals "$(value basemetals_source_commit)" require_merged OreSpawn "$orespawn_ref" -inputs="${RUNNER_TEMP:?}/forge52-release-dependencies" +inputs="${RUNNER_TEMP:?}/forge61-release-dependencies" mkdir -p "$inputs" power="$inputs/basePower-$(value poweradvantage_version).jar" metals="$inputs/BaseMetals-$(value basemetals_version).jar" @@ -57,8 +57,8 @@ public_jar basePower 1780140 "$(value poweradvantage_public_file_id)" "$(value p public_jar BaseMetals 240967 "$(value basemetals_public_file_id)" "$(value basemetals_deobf_sha256)" "$metals" public_jar OreSpawn 245586 "$(value orespawn_public_file_id)" "$(value orespawn_deobf_sha256)" "$orespawn" -installer="$inputs/forge-1.21.1-52.1.0-installer.jar" -download 'https://maven.minecraftforge.net/net/minecraftforge/forge/1.21.1-52.1.0/forge-1.21.1-52.1.0-installer.jar' \ +installer="$inputs/forge-1.21.11-61.1.0-installer.jar" +download 'https://maven.minecraftforge.net/net/minecraftforge/forge/1.21.11-61.1.0/forge-1.21.11-61.1.0-installer.jar' \ "$(value forge_installer_sha256)" "$installer" { printf 'power_ref=%s\n' "$power_ref" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d501558..eb7544f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,16 +1,16 @@ -name: baseElectric 1.21.1 CI +name: baseElectric 1.21.11 CI on: push: - branches: [master-1.21.1, 'feature/**'] + branches: [master-1.21.11, 'feature/**'] pull_request: - branches: [master-1.21.1] + branches: [master-1.21.11] permissions: contents: read concurrency: - group: baseelectric-1.21.1-${{ github.workflow }}-${{ github.ref }} + group: baseelectric-1.21.11-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: @@ -62,7 +62,7 @@ jobs: -Porg.gradle.java.installations.auto-download=false" >> "$GITHUB_ENV" - name: Set up Gradle uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6 - - name: Verify the Forge 52 build inputs + - name: Verify the Forge 61 build inputs shell: bash env: ORESPAWN_REF: ${{ steps.public-pins.outputs.orespawn_ref }} @@ -74,33 +74,33 @@ jobs: test "$(git -C "$orespawn" rev-parse HEAD)" = "$ORESPAWN_REF" test "$(git -C "$power" rev-parse HEAD)" = "$POWER_REF" mavenizer="$orespawn/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar" - printf '%s %s\n' '019032A4A26ECB473D403EF017054D5892CE59A9904E8831B452287CD756397E' "$mavenizer" | sha256sum -c - + printf '%s %s\n' 'B36CA046DB72E30F27BD38E02B4AE34274ADB51AE1D65BAF9E1D07763755682E' "$mavenizer" | sha256sum -c - echo "MAVENIZER=$mavenizer" >> "$GITHUB_ENV" - name: Build and audit release artifacts shell: bash run: | ./gradlew $MMD_GRADLE_TOOLCHAINS clean check build javadoc verifyReleaseDependencies verifyReleaseArtifacts \ writeReleaseChecksums verifyEclipseProductionClasspath --no-build-cache --no-daemon --stacktrace \ - "-Pforge52MavenizerJar=$MAVENIZER" "-PpowerAdvantageDeobfJar=$POWER_PLAYER" \ + "-Pforge61MavenizerJar=$MAVENIZER" "-PpowerAdvantageDeobfJar=$POWER_PLAYER" \ "-PbaseMetalsDeobfJar=$METALS_PLAYER" "-PoreSpawnDeobfJar=$ORESPAWN_PLAYER" \ "-PforgeInstallerJar=$FORGE_INSTALLER" - name: Upload audited release candidate uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: baseElectric-1.21.1-${{ github.sha }} + name: baseElectric-1.21.11-${{ github.sha }} if-no-files-found: error retention-days: 30 path: | - build/libs/baseElectric-2.2.15.121011.jar - build/libs/baseElectric-2.2.15.121011-sources.jar - build/libs/baseElectric-2.2.15.121011-javadoc.jar + build/libs/baseElectric-2.2.16.121111.jar + build/libs/baseElectric-2.2.16.121111-sources.jar + build/libs/baseElectric-2.2.16.121111-javadoc.jar build/release/SHA256SUMS CHANGELOG.txt - name: Upload diagnostics on failure if: failure() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: baseElectric-1.21.1-diagnostics-${{ github.sha }} + name: baseElectric-1.21.11-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 653688a3..d0771d40 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,9 +2,9 @@ name: CodeQL on: push: - branches: [master-1.21.1, 'feature/**'] + branches: [master-1.21.11, 'feature/**'] pull_request: - branches: [master-1.21.1] + branches: [master-1.21.11] permissions: contents: read @@ -12,7 +12,7 @@ permissions: security-events: write concurrency: - group: baseelectric-1.21.1-${{ github.workflow }}-${{ github.ref }} + group: baseelectric-1.21.11-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: @@ -64,7 +64,7 @@ jobs: -Porg.gradle.java.installations.auto-download=false" >> "$GITHUB_ENV" - name: Set up Gradle uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6 - - name: Verify the Forge 52 build inputs + - name: Verify the Forge 61 build inputs shell: bash env: ORESPAWN_REF: ${{ steps.public-pins.outputs.orespawn_ref }} @@ -76,7 +76,7 @@ jobs: test "$(git -C "$orespawn" rev-parse HEAD)" = "$ORESPAWN_REF" test "$(git -C "$power" rev-parse HEAD)" = "$POWER_REF" mavenizer="$orespawn/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar" - printf '%s %s\n' '019032A4A26ECB473D403EF017054D5892CE59A9904E8831B452287CD756397E' "$mavenizer" | sha256sum -c - + printf '%s %s\n' 'B36CA046DB72E30F27BD38E02B4AE34274ADB51AE1D65BAF9E1D07763755682E' "$mavenizer" | sha256sum -c - echo "MAVENIZER=$mavenizer" >> "$GITHUB_ENV" - name: Initialize CodeQL uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4 @@ -87,7 +87,7 @@ jobs: shell: bash run: | ./gradlew $MMD_GRADLE_TOOLCHAINS classes verifyReleaseDependencies --rerun-tasks --no-build-cache --no-daemon --stacktrace \ - "-Pforge52MavenizerJar=$MAVENIZER" "-PpowerAdvantageDeobfJar=$POWER_PLAYER" \ + "-Pforge61MavenizerJar=$MAVENIZER" "-PpowerAdvantageDeobfJar=$POWER_PLAYER" \ "-PbaseMetalsDeobfJar=$METALS_PLAYER" "-PoreSpawnDeobfJar=$ORESPAWN_PLAYER" - name: Analyze uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4 diff --git a/.github/workflows/validate-gradle-build.yml b/.github/workflows/validate-gradle-build.yml index 2f2c732b..b37dfc94 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.21.1 + - master-1.21.11 - 'feature/**' pull_request: branches: - - master-1.21.1 + - master-1.21.11 permissions: contents: read diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 89207e99..7a0fea92 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,14 @@ +baseElectric 2.2.16.121111 (Minecraft 1.21.11 / Forge) + +- Port to Forge 61.1.0 with basePower 2.4.15.121111 and Java 21. +- Preserve machine state, legacy aliases, battery charge and recipe progression. +- Use native render extraction, item definitions and per-PackType Forge resources. +- Keep the released 1.21.1 recipes, progression and world upgrade behavior. +- Require Base Metals 3.1.2.121111 on both client and server in Forge metadata. +- Use the verified public basePower and Base Metals releases. +- Retain the combined machine, upgrade, graphical and two-world endurance results under their original tested jar hashes. +- Run native resource checks without an interactive terminal while retaining strict warning and error checks. + baseElectric 2.2.15.121011 (Minecraft 1.21.1 / Forge) - Bring baseElectric to Minecraft 1.21.1 with basePower 2.4.14.121011. diff --git a/README.md b/README.md index 4651be1d..b6689c03 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,22 @@ baseElectric continues DrCyano's Electric Advantage. It adds electric machines, generation, storage, automation and defence to basePower. Its equipment appears in the shared basePower creative tab. -This version targets Minecraft **1.21.1**, Forge **52.1.0**, official mappings -with MCP **20240808.132146**, ForgeGradle **7.0.34**, Gradle **9.6.1**, and Java -**21**. The version is **2.2.15.121011**. It requires basePower **2.4.14.121011**. -The coordinated dependencies are Base Metals **3.1.2.121011** and OreSpawn -**4.1.0.121011**. All three dependency pins use merged source and verified public -downloads. CurseForge, Maven and GitHub releases use the same checked player jar. -See the [1.21.1 notes](docs/NATIVE1211.md) for compatibility and verification status. +baseElectric **2.2.16.121111** runs on Minecraft **1.21.11**, Forge **61.1.0**, +official mappings with MCP **20251223.124241**, ForgeGradle **7.0.34**, Gradle +**9.6.1**, and Java **21**. It requires +[basePower **2.4.15.121111**](https://www.curseforge.com/minecraft/mc-mods/basepower/files/9566998). +[Base Metals **3.1.2.121111**](https://www.curseforge.com/minecraft/mc-mods/base-metals/files/9566738) +is also **REQUIRED** on both client and server; +Forge enforces this dependency. The coordinated OreSpawn version is +**4.1.0.121111**. This version has been accepted for release but is not yet published. +See the [1.21.11 notes](docs/NATIVE12111.md) for compatibility and verification status. + +Combined machine, upgrade, graphical and two-world 30-minute endurance checks +passed before the released dependency retarget. The full record and its manual-test limits are in +basePower's `docs/1.21.11/QUALIFICATION.md`. Those limits still apply. +Publication is waiting for the final combined restart/endurance checks and +baseSteam's public release. The released dependency pins are recorded in +`gradle.properties`. Back up your world and try the upgrade on a copy. Replace Electric Advantage and Power Advantage with baseElectric and basePower; do not install both sets. @@ -30,20 +39,20 @@ node tools/verify-native-port.js node tools/generate-recipe-unlocks.js --check ``` -For a full local build, supply files matching the exact coordinated source -and jar pins recorded in `gradle.properties`. The current basePower pin is an -approved local commit, not merged or publicly released: +For a full local build, use the exact dependency jars recorded in +`gradle.properties`. The sibling paths are the defaults and these flags are +optional path overrides: ```text --PpowerAdvantageRuntimeJar=/path/to/basePower-2.4.14.121011.jar --PbaseMetalsRuntimeJar=/path/to/BaseMetals-3.1.2.121011.jar --PforgeInstallerJar=/path/to/forge-1.21.1-52.1.0-installer.jar +-PpowerAdvantageRuntimeJar=/path/to/basePower-2.4.15.121111.jar +-PbaseMetalsRuntimeJar=/path/to/BaseMetals-3.1.2.121111.jar +-PforgeInstallerJar=/path/to/forge-1.21.11-61.1.0-installer.jar ``` -Forge 52 uses the ordinary native jar for both play and development. The former +Forge 61 uses the ordinary native jar for both play and development. The former `*DeobfJar` path flags remain aliases for the same bytes. OreSpawn and the -Mavenizer fixture default to the sibling `MinecraftMineralogy/OS1211/OreSpawn` -checkout. Use `-PoreSpawnRuntimeJar` and `-Pforge52MavenizerJar` to override paths. +Mavenizer fixture default to the sibling `MinecraftMineralogy/OS12111/OreSpawn` +checkout. Use `-PoreSpawnRuntimeJar` and `-Pforge61MavenizerJar` to override paths. For the prepared cache, use `--offline` with `ORESPAWN_MAVENIZER_OFFLINE=true`. ```text @@ -51,12 +60,15 @@ For the prepared cache, use `--offline` with `ORESPAWN_MAVENIZER_OFFLINE=true`. ``` Use `gradlew.bat` on Windows. Output jars go to `build/libs`. Dependencies -remain separate mods. The 1.21.1 CI and CodeQL jobs require merged source pins +remain separate mods. The 1.21.11 CI and CodeQL jobs require merged source pins and checksum-matching public dependencies before checkout or compilation. Local jars do not satisfy that gate. ## Verification +The current local checks pass 114 unit tests, 25 native resource tests and +114 tests from fresh Eclipse compiler output, with no failures or skips. + Run `runGameTestServer` with the same pinned mod inputs, an existing accepted EULA passed as `-PelectricGameTestEula=`, and a new directory passed as `-PelectricGameTestRunDirectory=build/port-evidence/`. The test code and diff --git a/build.gradle b/build.gradle index b4b227dc..9483094a 100644 --- a/build.gradle +++ b/build.gradle @@ -61,7 +61,7 @@ def pinnedFile = { String property, String expected, String fallback = null -> input } -apply from: 'gradle/forge52-mavenizer.gradle' +apply from: 'gradle/forge61-mavenizer.gradle' java { toolchain { @@ -89,10 +89,13 @@ tasks.named('test', Test) { } afterSuite { descriptor, result -> if (!descriptor.parent && filter.includePatterns.empty && filter.commandLineIncludePatterns.empty - && (result.testCount != 106 || result.skippedTestCount != 0)) { - throw new GradleException("Expected 106 tests with no skips, got ${result.testCount} tests and ${result.skippedTestCount} skips") + && (result.testCount != 114 || result.skippedTestCount != 0)) { + throw new GradleException("Expected 114 tests with no skips, got ${result.testCount} tests and ${result.skippedTestCount} skips") } } + doFirst { + systemProperty 'baseelectric.nativePackClasspath', classpath.asPath + } } tasks.withType(Javadoc).configureEach { @@ -126,6 +129,8 @@ def electricGameTestRunDirectory = layout.projectDirectory.dir( sourceSets { gameTestValidation { java.srcDir 'src/gametest/java' + resources.srcDir 'src/gametest/resources' + resources.exclude 'gameteststructures/**' compileClasspath += sourceSets.main.output runtimeClasspath += sourceSets.main.output } @@ -161,6 +166,7 @@ minecraft { register('gameTestServer') { workingDir.set(electricGameTestRunDirectory) systemProperty 'forge.enabledGameTestNamespaces', project.mod_id + args '--tests', 'baseelectric:*', '--report', 'game-test-results.xml' mods { baseelectric { source sourceSets.gameTestValidation } } environment 'MOD_CLASSES', "${mod_id}%%${gameTestModOutput.get().asFile}" } @@ -180,7 +186,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.21.1 launches.' + description = 'Merges classes and processed resources for Forge 1.21.11 launches.' dependsOn tasks.named('classes') from sourceSets.main.output into forgeRunModClassesDirectory @@ -231,6 +237,20 @@ tasks.withType(JavaExec).configureEach { Set splitOutputs = sourceSets.collectMany { it.output.files }.collect { it.canonicalFile } as Set classpath = files(gameTestModOutput, classpath.files.findAll { !splitOutputs.contains(it.canonicalFile) }) } + doLast { + File report = new File(electricGameTestRunDirectory.asFile, 'game-test-results.xml') + if (!report.isFile()) throw new GradleException('Native Electric GameTest report is missing') + def document = javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(report) + def cases = document.getElementsByTagName('testcase') + Set names = (0.. + Set expected = ['drillupgradesandtransferslegacybattery', 'recipeavailabilitydoesnotremovediscovery', + 'siliconandsolderresolverealmaterialtags', 'turretusesnativeupdatepacket'] + .collect { "baseelectric:${it}".toString() } as Set + if (cases.length != 4 || names != expected + || ['failure', 'error', 'skipped'].any { document.getElementsByTagName(it).length != 0 }) { + throw new GradleException("Expected all four native Electric tests without skips/failures, got ${names}") + } + } } } @@ -246,6 +266,21 @@ repositories { maven { url = 'https://libraries.minecraft.net/' } } +// The mapped Forge module intentionally has no installer classifier. +repositories.configureEach { + if (name != 'ForgeInstallerArtifacts') { + content { notForConfigurations('forgeInstallerArtifact') } + } +} +repositories.maven { + name = 'ForgeInstallerArtifacts' + url = 'https://maven.minecraftforge.net/' + content { + onlyForConfigurations('forgeInstallerArtifact') + includeModule('net.minecraftforge', 'forge') + } +} + def committedPins = new Properties() file('gradle.properties').withInputStream { committedPins.load(it) } def requireCommittedPins = { String prefix -> @@ -264,21 +299,23 @@ def requirePowerPin = { || !(project.poweradvantage_source_ref ==~ /[a-f0-9]{40}/) || ![project.poweradvantage_deobf_sha256, project.poweradvantage_runtime_sha256] .every { it ==~ /[A-F0-9]{64}/ }) { - throw new GradleException('The owner-approved basePower 1.21.1 source and artifact pins are required.') + throw new GradleException('The owner-approved basePower 1.21.11 source and artifact pins are required.') } } // Resolve and check only the dependencies required by the selected tasks. +def powerDefaultJar = "../../PowerAdvantage/build/libs/basePower-${project.poweradvantage_version}.jar" +def metalsDefaultJar = "../../../../BaseMetals/.verification-basemetals12111/Advantage shared hook/build/libs/BaseMetals-${project.basemetals_version}.jar" def powerAdvantageDeobfJar = providers.provider { requirePowerPin() pinnedFile('powerAdvantageDeobfJar', project.poweradvantage_deobf_sha256, - providers.gradleProperty('powerAdvantageRuntimeJar').orNull) + providers.gradleProperty('powerAdvantageRuntimeJar').getOrElse(powerDefaultJar)) } def baseMetalsDeobfJar = providers.provider { requireCommittedPins('basemetals_') pinnedFile('baseMetalsDeobfJar', project.basemetals_deobf_sha256, - providers.gradleProperty('baseMetalsRuntimeJar').orNull) + providers.gradleProperty('baseMetalsRuntimeJar').getOrElse(metalsDefaultJar)) } -def oreSpawnProject = '../../../../MinecraftMineralogy/OS1211/OreSpawn' +def oreSpawnProject = '../../../../MinecraftMineralogy/OS12111/OreSpawn' def oreSpawnDeobfJar = providers.provider { requireCommittedPins('orespawn_') pinnedFile('oreSpawnDeobfJar', project.orespawn_deobf_sha256, @@ -288,6 +325,18 @@ def oreSpawnDeobfJar = providers.provider { def nativeForge = minecraft.dependency( "net.minecraftforge:forge:${project.minecraft_version}-${project.forge_version}") +def forgeInstallerConfiguration = configurations.create('forgeInstallerArtifact') { + canBeConsumed = false + canBeResolved = true + transitive = false +} +dependencies.add(forgeInstallerConfiguration.name, + "net.minecraftforge:forge:${project.minecraft_version}-${project.forge_version}:installer@jar") +def forgeInstallerJar = providers.provider { + String explicit = providers.gradleProperty('forgeInstallerJar').orNull + pinnedFile('forgeInstallerJar', project.forge_installer_sha256, + explicit ?: forgeInstallerConfiguration.singleFile.absolutePath) +} dependencies { implementation nativeForge // basePower is required at runtime but remains a separate mod jar. @@ -317,34 +366,42 @@ tasks.register('compileNativeApiDiagnostics', JavaCompile) { group = 'verification' description = 'Compiles sibling-independent native APIs; never builds a candidate jar.' source fileTree('src/main/java') { - include '**/util/crafting/*.java', '**/blocks/Ore.java', '**/graphics/BufferedQuads.java' + include '**/util/crafting/*.java', '**/util/farming/*.java', '**/blocks/Ore.java', '**/graphics/BufferedQuads.java', + '**/graphics/ElectricRenderTypes.java', '**/util/RegistryIds.java', '**/util/LegacyNbt.java', + '**/machines/ElectricOperationalSound.java' } classpath = nativeResourceCheckClasspath.get() destinationDirectory = layout.buildDirectory.dir('classes/native-api-diagnostics') } def compileNativeResourceChecks = tasks.register('compileNativeResourceChecks', JavaCompile) { + dependsOn tasks.named('compileNativeApiDiagnostics') source fileTree('src/test/java') { include '**/BlockLootResourceTest.java', '**/RecipeResourceTest.java', '**/RecipeUnlockContractTest.java', '**/RecipeRegistrationThreadTest.java', '**/NativeTestBootstrap.java', '**/LegacyBatteryDataTest.java', - '**/BuildWorkflowContractTest.java', '**/ShaderResourceContractTest.java', '**/DatapackLayoutTest.java' + '**/NativePackRangeContractTest.java', '**/NativePackResourceProof.java', + '**/BuildWorkflowContractTest.java', '**/ShaderResourceContractTest.java', '**/DatapackLayoutTest.java', + '**/RecipeDeconstructorTest.java' } - classpath = nativeResourceCheckClasspath.get() + classpath = nativeResourceCheckClasspath.get() + files(layout.buildDirectory.dir('classes/native-api-diagnostics')) destinationDirectory = nativeResourceCheckClasses } tasks.register('nativeResourceChecks', Test) { group = 'verification' - description = 'Checks Electric resources against native Forge 52 without sibling mod jars.' - dependsOn compileNativeResourceChecks + description = 'Checks Electric resources against native Forge 61 without sibling mod jars.' + dependsOn compileNativeResourceChecks, tasks.named('processResources') useJUnit() testClassesDirs = files(nativeResourceCheckClasses) - classpath = testClassesDirs + nativeResourceCheckClasspath.get() + classpath = testClassesDirs + nativeResourceCheckClasspath.get() + files(layout.buildDirectory.dir('classes/native-api-diagnostics')) afterSuite { descriptor, result -> - if (!descriptor.parent && (result.testCount != 17 || result.skippedTestCount != 0)) { - throw new GradleException("Expected 17 native resource tests without skips, got ${result.testCount}/${result.skippedTestCount}") + if (!descriptor.parent && (result.testCount != 25 || result.skippedTestCount != 0)) { + throw new GradleException("Expected 25 native resource tests without skips, got ${result.testCount}/${result.skippedTestCount}") } } + doFirst { + systemProperty 'baseelectric.nativePackClasspath', classpath.asPath + } } def clientValidationSources = fileTree('src/test/java') { @@ -419,13 +476,13 @@ def releaseJar = tasks.named('jar', Jar) tasks.register('releaseJar') { group = 'build' - description = 'Builds the native Forge 52 player jar.' + description = 'Builds the native Forge 61 player jar.' dependsOn releaseJar } tasks.register('deobfJar') { group = 'build' - description = 'Builds the same native Forge 52 jar used for development and play.' + description = 'Builds the same native Forge 61 jar used for development and play.' dependsOn tasks.named('jar') } @@ -443,10 +500,33 @@ tasks.named('sourcesJar', Jar) { } } +def javadocLegalNames = ['LICENSE', 'ADDITIONAL_LICENSE_INFO', 'ASSEMBLY_EXCEPTION'] +tasks.named('javadoc', Javadoc) { + inputs.files(javadocTool.map { tool -> + javadocLegalNames.collect { tool.metadata.installationPath.file("legal/java.base/${it}").asFile } + }) + doLast { + File legalRoot = javadocTool.get().metadata.installationPath.dir('legal/java.base').asFile + javadocLegalNames.each { name -> + if (!new File(legalRoot, name).isFile()) { + throw new GradleException("Selected JDK is missing legal/java.base/${name}") + } + } + // Windows JDK module notices point outside the generated documentation. + project.copy { + from legalRoot + include javadocLegalNames + into new File(destinationDir, 'legal') + filesMatching(javadocLegalNames, normalizeArchiveLineEndings) + } + } +} + tasks.named('javadocJar', Jar) { filteringCharset = 'UTF-8' archiveClassifier = 'javadoc' filesMatching(archiveTextPatterns, normalizeArchiveLineEndings) + filesMatching('**/*.svg', normalizeArchiveLineEndings) manifest { attributes([ 'Maven-Artifact' : "${project.group}:${base.archivesName.get()}:${project.version}:javadoc", @@ -475,21 +555,24 @@ tasks.register('verifyReleaseConfiguration') { requirePowerPin() requireCommittedPins('basemetals_') requireCommittedPins('orespawn_') + requireCommittedPins('forge_') def pack = new JsonSlurper().parse(file('src/main/resources/pack.mcmeta')).pack - if (pack.pack_format != 34 || pack.supported_formats != [min_inclusive: 34, max_inclusive: 48]) { - throw new GradleException('Minecraft 1.21.1 requires resource format 34 and data format 48') + if (pack.min_format != [94, 1] || pack.max_format != [94, 1] + || pack.containsKey('pack_format') || pack.containsKey('supported_formats') + || !(file('src/main/resources/META-INF/mods.toml').text =~ /(?m)^showAsResourcePack=false$/)) { + throw new GradleException('Root metadata must declare data 94.1 with the native hidden Forge client pack') } - if (project.mod_version != '2.2.15.121011') { + if (project.mod_version != '2.2.16.121111') { throw new GradleException("Unexpected baseElectric release version: ${project.mod_version}") } - if (project.minecraft_version != '1.21.1' - || project.minecraft_version_range != '[1.21.1]' - || project.forge_version != '52.1.0' - || project.forge_version_range != '[52.1.0,53)' - || project.loader_version_range != '[52,)' + if (project.minecraft_version != '1.21.11' + || project.minecraft_version_range != '[1.21.11]' + || project.forge_version != '61.1.0' + || project.forge_version_range != '[61.1.0,62)' + || project.loader_version_range != '[61,)' || project.mapping_channel != 'official' - || project.mapping_version != '1.21.1' - || project.mcp_version != '20240808.132146') { + || project.mapping_version != '1.21.11' + || project.mcp_version != '20251223.124241') { throw new GradleException('Unexpected Minecraft, Forge, or mappings target') } if (project.loader_name != 'forge' || project.loader_code != '1' @@ -509,15 +592,15 @@ tasks.register('verifyReleaseConfiguration') { } if (project.cf_requirements != 'basepower,base-metals' || project.cf_optionals != '' - || project.cf_versions != '1.21.1') { + || project.cf_versions != '1.21.11') { throw new GradleException('Unexpected CurseForge dependency or game-version metadata') } - if (project.poweradvantage_version != '2.4.14.121011' + if (project.poweradvantage_version != '2.4.15.121111' || project.poweradvantage_source_repository != 'MinecraftModDevelopmentMods/basePower') { throw new GradleException('Unexpected basePower compile dependency identity') } - if (!(project.basemetals_version ==~ /3\.\d+\.\d+\.121011/) - || project.orespawn_version != '4.1.0.121011' + if (!(project.basemetals_version ==~ /3\.\d+\.\d+\.121111/) + || project.orespawn_version != '4.1.0.121111' || !(project.basemetals_source_commit ==~ /[a-f0-9]{40}/) || !(project.basemetals_deobf_sha256 ==~ /[A-F0-9]{64}/) || !(project.basemetals_runtime_sha256 ==~ /[A-F0-9]{64}/) @@ -525,24 +608,24 @@ tasks.register('verifyReleaseConfiguration') { || project.orespawn_deobf_sha256 != project.orespawn_runtime_sha256 || project.basemetals_deobf_sha256 != project.basemetals_runtime_sha256 || project.poweradvantage_deobf_sha256 != project.poweradvantage_runtime_sha256 - || project.forge_installer_sha256 != 'F1B620F2879AD6A5BBE15DABA4D8F81EAB9F5E08004967604960B98996BDEBC4') { + || project.forge_installer_sha256 != '8BD1724EAEAF26F51DACFB7FDC46D79E9B640705B70D5F0019ED38907145EB48') { throw new GradleException('Unexpected native dependency pins') } String mainSource = file( 'src/main/java/zone/moddev/mc/baseelectric/ElectricAdvantage.java').getText('UTF-8') if (!mainSource.contains('MODID = "baseelectric"') - || !mainSource.contains('VERSION = "2.2.15.121011"')) { + || !mainSource.contains('VERSION = "2.2.16.121111"')) { throw new GradleException('baseElectric source identity changed') } String metadata = file('src/main/resources/META-INF/mods.toml').getText('UTF-8').replace('\r\n', '\n') ['modId="baseelectric"', 'displayName="baseElectric"', 'modId="basepower"', 'modId="basemetals"', - 'versionRange="[2.4.14.121011,3.0.0)"', 'versionRange="[3.1.2.121011,4.0.0)"'].each { marker -> + 'versionRange="[2.4.15.121111,3.0.0)"', 'versionRange="[3.1.2.121111,4.0.0)"'].each { marker -> if (!metadata.contains(marker)) { throw new GradleException("Source mods.toml is missing ${marker}") } } - if (!metadata.contains('modId="basemetals"\nmandatory=false')) { - throw new GradleException('Base Metals must remain Forge-optional; CurseForge installs it for players') + if (!metadata.contains('modId="basemetals"\nmandatory=true')) { + throw new GradleException('Base Metals must be required by Forge on both client and server') } } } @@ -567,14 +650,14 @@ def auditModInput = { File jarFile, String modId, String version, List r tasks.register('verifyLocalNativeInputs') { group = 'verification' - description = 'Verifies explicit Base Metals and OreSpawn 1.21.1 development and player JARs.' + description = 'Verifies explicit Base Metals and OreSpawn 1.21.11 development and player JARs.' dependsOn tasks.named('verifyReleaseConfiguration') doLast { auditModInput(baseMetalsDeobfJar.get(), 'basemetals', project.basemetals_version, ['zone/moddev/mc/basemetals/api/migration/Legacy112MigrationExtension.class', 'zone/moddev/mc/basemetals/recipe/CrushingRecipe.class']) auditModInput(pinnedFile('baseMetalsRuntimeJar', project.basemetals_runtime_sha256, - providers.gradleProperty('baseMetalsDeobfJar').orNull), + providers.gradleProperty('baseMetalsDeobfJar').getOrElse(metalsDefaultJar)), 'basemetals', project.basemetals_version, []) auditModInput(oreSpawnDeobfJar.get(), 'orespawn', project.orespawn_version, []) auditModInput(pinnedFile('oreSpawnRuntimeJar', project.orespawn_runtime_sha256, @@ -591,9 +674,9 @@ tasks.register('verifyLocalRuntimeInputs') { doLast { requirePowerPin() auditModInput(pinnedFile('powerAdvantageRuntimeJar', project.poweradvantage_runtime_sha256, - providers.gradleProperty('powerAdvantageDeobfJar').orNull), + providers.gradleProperty('powerAdvantageDeobfJar').getOrElse(powerDefaultJar)), 'basepower', project.poweradvantage_version, []) - File installer = pinnedFile('forgeInstallerJar', project.forge_installer_sha256) + File installer = forgeInstallerJar.get() logger.lifecycle("Verified Forge installer: ${project.forge_installer_sha256} ${installer}") } } @@ -734,7 +817,7 @@ tasks.register('verifyReleaseArtifacts') { .getText(StandardCharsets.UTF_8.name()) if (!metadata.contains('modId="baseelectric"') || !metadata.contains("version=\"${project.mod_version}\"") - || !metadata.contains('modId="basemetals"\nmandatory=false')) { + || !metadata.contains('modId="basemetals"\nmandatory=true')) { throw new GradleException('Packaged mods.toml identity or version is incorrect') } def manifest = new Manifest(zip.getInputStream(zip.getEntry('META-INF/MANIFEST.MF'))).mainAttributes @@ -772,6 +855,21 @@ tasks.register('verifyReleaseArtifacts') { if (javadocZip.getEntry('index.html') == null) { throw new GradleException('Javadoc jar is missing index.html') } + ['copy.svg', 'link.svg'].each { name -> + def entry = javadocZip.getEntry(name) + if (entry == null || javadocZip.getInputStream(entry).getText('UTF-8').contains('\r')) { + throw new GradleException("Javadoc resource ${name} must use canonical LF line endings") + } + } + File legalRoot = tasks.named('javadoc', Javadoc).get().javadocTool.get() + .metadata.installationPath.dir('legal/java.base').asFile + javadocLegalNames.each { name -> + def entry = javadocZip.getEntry("legal/${name}") + String expectedLegal = new File(legalRoot, name).getText('UTF-8').replace('\r\n', '\n') + if (entry == null || javadocZip.getInputStream(entry).getText('UTF-8') != expectedLegal) { + throw new GradleException("Javadoc legal/${name} must contain the selected JDK's full canonical legal text") + } + } } } } @@ -896,7 +994,7 @@ tasks.register('validateMavenReleaseCredentials') { group = 'publishing' description = 'Rejects remote publication from this local port.' doLast { - throw new GradleException('Remote Maven publication is disabled on the local 1.21.1 port.') + throw new GradleException('Remote Maven publication is disabled on the local 1.21.11 port.') } } @@ -1299,7 +1397,7 @@ tasks.register('verifyEclipseProductionClasspath') { || !programArguments.startsWith('--main net.minecraftforge.bootstrap.ForgeBootstrap ') || !programArguments.contains(" -- --launchTarget ${target} ") || !vmArguments.contains('--add-opens java.base/java.lang.invoke=ALL-UNNAMED')) { - throw new GradleException("${name} does not define the Forge 52 bootstrap and native launch target") + throw new GradleException("${name} does not define the Forge 61 bootstrap and native launch target") } ['--cache', '--metadata', '--to-srg', '--to-obf'].each { option -> def argument = programArguments =~ /(?:^|\s)${option}\s+(?:"([^"]+)"|([^"\s]+))(?=\s+--|$)/ @@ -1484,6 +1582,8 @@ tasks.register('verifyRecipeTagGuards') { } } else if (node instanceof Collection) { node.each { collectTags(it, tags) } + } else if (node instanceof String && node.startsWith('#forge:')) { + tags.add(node.substring(1)) } } fileTree(recipeRoot) { include '**/*.json' }.files.sort().each { File recipeFile -> diff --git a/docs/FORGE61-RESOURCE-METADATA.md b/docs/FORGE61-RESOURCE-METADATA.md new file mode 100644 index 00000000..874a1a2a --- /dev/null +++ b/docs/FORGE61-RESOURCE-METADATA.md @@ -0,0 +1,81 @@ +# Forge 61 Resource Metadata + +This applies to the exact Forge 1.21.11-61.1.0 target, not newer loaders. + +## Mod Metadata + +Keep pack.mcmeta at the mod root, declaring server data format 94.1: + +```json +{"pack":{"description":"baseElectric","min_format":[94,1],"max_format":[94,1]}} +``` + +Keep showAsResourcePack=false at the top level of META-INF/mods.toml. +It defaults to false, but the explicit value protects this contract. + +ResourcePackLoader uses PathPackResources for each mod. On the client it +combines hidden mods into DelegatingPackResources named mod_resources, +with native client metadata for 75.x. On the server it exposes the mod's +PathPackResources and reads the root's 94.1 metadata. A mod with +showAsResourcePack=true cannot use this hidden-client metadata strategy. + +Do not decode the server-format root as if it were the effective client +pack. The negative test still proves that a raw 94.1 resource pack does not +accept client format 75.0. Both effective native packs must be verified. + +A single raw [75,0] through [94,1] declaration fails server decoding because +the server's pre-minor threshold is 81 and requires legacy fields there. +The client's threshold is 64, so it rejects those legacy fields at 75. +Neither fallback metadata nor ignored diagnostic messages fixes that. + +Omitting pack.mcmeta is not a solution. The native mod PathResourcesSupplier +returns null metadata for both PackTypes. Pack.readPackMetadata then reports +missing metadata, and ResourcePackLoader enters its broken-resources warning +path. ForgeDevLocator's development-only fallback writes obsolete format 18; +it is not correct per-PackType metadata for a packaged 1.21.11 mod. + +## Native APIs + +MetadataSectionSerializer is replaced by MetadataSectionType. A native +PackResources implementation overrides: + +```java +public T getMetadataSection(MetadataSectionType section) throws IOException +``` + +PackMetadataSection takes a Component and InclusiveRange, not +an integer pack version. Use PackMetadataSection.forPackType(type) for the +correct codec, SharedConstants.getCurrentVersion().packVersion(type) for the +current format, and Pack.readMetaAndCreate(..., type, ...) when creating a +built-in pack. A server-only MaterialPolicyPack should use SERVER_DATA. +Native DelegatingPackResources is an example of directly supplied metadata. + +## Separate Loader Defect + +Forge 61.1.0 ResourcePackLoader.findPacks always gets its comparison version +from DetectedVersion.BUILT_IN.packVersion(CLIENT_RESOURCES), even for server +data. A correctly declared 94.1 server mod pack is therefore labelled +TOO_NEW by that discovery method. Re-reading the same native supplier with +the actual SERVER_DATA version returns COMPATIBLE, and every server resource +is accessible. The test receipt records the discrepancy explicitly. + +This is distinct from codec failure. It is not fixed or hidden here, and +server compatibility-label acceptance remains a parent/platform decision. +Do not change data to format 75, suppress warnings, or fake compatibility. + +## Proof + +NativePackResourceProof runs a separate JVM, builds a resource-only fixture +jar from Gradle's processed Electric resources, parses it with real SecureJar +and ModFile, and calls ResourcePackLoader through PackRepository. It then +opens the actual client/server packs and MultiPackResourceManager instances. +All 306 client and 160 server files are compared byte for byte with the input. +The effective metadata round-trips through the appropriate native codec, +rejects the opposite PackType's version and rejects out-of-range versions. +The Log4j appender observes WARN/ERROR messages without filtering existing +appenders, and the parent also checks the complete child log. Any diagnostic +fails the proof. The test child has its own working directory and leaves +its jar, logs and receipt under ignored build/native-pack-resources/. + +This proves resource/metadata behavior, not a full gameplay client/server +launch, basePower compatibility or the Electric release artifact. diff --git a/docs/NATIVE12111.md b/docs/NATIVE12111.md new file mode 100644 index 00000000..58c8d8dd --- /dev/null +++ b/docs/NATIVE12111.md @@ -0,0 +1,187 @@ +# Electric on Minecraft 1.21.11 + +The local baseElectric 2.2.16.121111 port targets Forge 61.1.0, official +1.21.11 mappings, MCP 20251223.124241, Java 21, ForgeGradle 7.0.34 and +Gradle 9.6.1. The source baseline is the manually accepted 1.21.1 commit +`c0ee871f43c5f0691efd85c1e4abb6a1ab70ede3`. +The port is reconciled with merged 1.21.1 head +`b81645579c3330476b84149402c3ce78183df85f`, retaining its release history and guards. + +## Compatibility + +Before the released-pin retarget, the frozen 54662C9A player jar, with Power +C98D, Steam F23D, Base Metals 598D +and OreSpawn DE39, has completed the supported automated family qualification. +This version is accepted for release but is not yet published. basePower's +`docs/1.21.11/QUALIFICATION.md` records the complete hashes and scope. +The current frozen jars pass 132 finite machine jobs, restart and migration +tests, chunk/network and drill lifecycle tests, recipes, generation, oils and +graphical checks. Two 30-minute worlds pass cold restart, resumed work and +independent exact stopped-save replay. All nine family artifacts reproduce +from independent builds. Electric's current 114 unit tests, 25 native resource +tests, 114 tests from fresh Eclipse compiler output and four fresh source +GameTests pass. Live turbine animation, connected-player interaction and the +other explicit manual requirements are not converted into automated passes. + +Base Metals 3.1.2.121111 is REQUIRED on both client and server. Forge metadata +declares mandatory=true, version range [3.1.2.121111,4.0.0), AFTER ordering and +BOTH sides. A runtime without Base Metals is not a supported optional profile. +The approved local migration-hook pin remains separate from public releases. + +Persistent registrations, legacy Electric Advantage aliases, configuration +keys, root machine NBT, battery components and recipe progression are retained. +The 58 recipe files use native item and tag ingredients. All 50 discovery +advancements and all 64 track states retain their accepted contents. Native +item definitions point to the existing models and textures. + +Machine persistence uses native value input/output with a root map codec; +it does not introduce a new enclosing compound. Native block-entity removal +owns inventory drops. Renderer submission uses extracted state and the native +entity shader's no-cardinal-lighting mode, retaining lightmap, overlay and fog. + +Root pack metadata declares min=max [94,1] and mods.toml explicitly sets the +top-level showAsResourcePack=false. Forge's actual hidden client delegate +synthesizes 75.x metadata; the server uses the root's 94.1 metadata. Neither +omitted metadata nor a broad cross-PackType range is used. The child-JVM native +proof verifies all 306 client and 160 server files byte-for-byte without +warnings/errors. See FORGE61-RESOURCE-METADATA.md for the native path and the +separate Forge 61 server discovery TOO_NEW label defect. Both effective packs +are compatible with their actual native current version; mods.toml permits +only Minecraft 1.21.11. + +## Verification Boundaries + +The independent native resource/API checks do not require sibling mod jars. +They retain the previous 17 resource checks, add two native fabricator-plan +tests including root-NBT round-trips, and add three native pack range/path +checks, plus a native ModInfo dependency regression with an optional-metadata +negative control. Two further checks cover a real piped TERM=dumb child and +strict diagnostic rejection. The independent suite expects 25 tests. The +static audit retains all 106 accepted unit tests and four GameTests; the full +suite now expects 114 unit tests without skips. A static inventory check does +not establish that the full suite compiles or executes. + +The qualified local Power integration source was +41959572b11dce236df98f23e97c6a3868cdda03, with player/development SHA-256 +C98D2CF163BE2480D9AFB0023BBD2D92D401AE0D50BEF73191235BF3F83774A7. +This includes the required-Base-Metals metadata correction and the native +registry/DFU, description-prefix, atlas and biome-index repairs. This is a +LOCAL_SOURCE integration pin at that checkpoint, not a public release pin. +Base Metals then used the separately approved local migration hook +616d527e50e4bf0137eeb9c44fa586e34a0452a0 at SHA-256 +598D3FB0FF956EBCC67FE477A01CE393C75D0013AF0CE00A79E2072B63E9F2BA. +These inputs repair the shared migration RETURN hooks to mutate the same NBT +in place without cancelling the other mod's callback. Earlier 0240/6D24 inputs +and their receipts are retained, not relabelled as qualification of these bytes. +The earlier D8BA/598D and 71E0/598D candidates and their receipts are also +preserved, as are the C2 and D inputs and their scoped receipts. The D player +jar at 6FB613EECAE677A66BF4A9BEDACD632A621CFD61BC4981CAF2F5372BB89A0240 +remains held separately. Entry-by-entry comparison confirms Electric production +classes and resources are unchanged: only mods.toml and the provenance manifest +differ from D in the new player jar. The sources jar differs only in mods.toml; +the Javadoc jar is byte-identical. Graphical C2 receipts remain bound to C2, not relabelled +as current qualification. Combined/raw/endurance and manual gates remain +parent-owned. + +The required-dependency correction's native parser and static dependency +checks are separate from the prior D release/GameTest receipts: +the optional metadata first failed the native mandatory assertion, then the +correction passed all 23 independent tests without failures or skips and all +seven static audits. Release-configuration, recipe, layout and hygiene checks +also pass. At that metadata checkpoint, on the approved 4195957/C98D input, the +default no-path-override release suite passed with 46 forced tasks, 112 unit +tests in 33 suites and the 23 independent resource tests, all without failures +or skips. Dependency, +artifact, checksum, Javadoc and generated production Eclipse audits pass. +Actual Eclipse ECJ compiles all 88 main, 36 test, one GameTest and three client +sources; its current fresh Java 21 JUnit output passes all 114 tests without +failures, ignored tests or assumptions. Its restricted-JDK negative control +is rejected. +Player/source/Javadoc SHA-256 values are generated from actual bytes in +build/release/SHA256SUMS. OreSpawn, mod versions and publication state are +unchanged. Family qualification remains separate. + +The current test-only terminal correction passes 114 unit tests and all 25 +independent native resource checks. The real piped child uses the official +terminalconsoleappender 1.2.0 option -Dterminal.jline=false and TERM=dumb; +its native receipt confirms interactiveTerminalDisabled=true. Strict +WARN/ERROR/FATAL validation is unchanged, with six rejecting negative controls. +No logger filtering or warning allowlist is used. The player, sources and +Javadoc jars remain byte-identical to the qualified metadata candidate. + +Native ingredient-codec tests cover item strings, tag strings and alternative +arrays, including rejection of old item/tag objects. The live recipe GameTest +also decodes all 58 packaged recipe JSONs against actual runtime registries and +round-trips them through Recipe.CODEC. All four live GameTests passed on their +original candidates; no world/GameTest run is repeated for this metadata batch. +Native test functions and test-instance resources are registered explicitly; the run +selects baseelectric:* and requires the exact four successful IDs in its report. +The network oracle compares exact bytes of the current native recipe-book +display packet, rather than the obsolete full-recipe synchronization path. +Forge 61's old optional-ingredient encoder throws for shaped empty slots, and +network-unpacked shaped recipes cannot encode their original source JSON. +Both failed observations are retained without patching frozen Forge jars. + +Approved source/artifact pins are recorded and cannot be overridden. The +accepted 1.21.1 jars are not valid substitutes. Current supported combined and +graphical results are summarized above; their narrower receipt scopes remain. +The development GameTest log retains initial-config and upstream Power +method-annotation warnings; a successful +GameTest run is not a clean-log or graphical qualification. + +Final qualification must use one stable set of hashes, including actual +Eclipse ECJ main/test, GameTest and client-only scopes, the default build without +dependency path overrides, and independent cold/path-with-spaces reproduction. +Generated logs and failed receipts remain local under build/port-evidence. + +No whole-world upgrade, family gameplay, restart, client visual acceptance, +publication or release readiness is established by the independent checks. + +## Release Preparation + +Release acceptance does not change the retained automated/manual evidence +boundaries above. The current MERGED_SOURCE Power pin is the public +2.4.15.121111 release at 9b0043483d79d3e575895f12aeb0dde7ef6c4890, +[CurseForge file 9566998](https://www.curseforge.com/minecraft/mc-mods/basepower/files/9566998), +with the same C98D player/development bytes. Base Metals uses public merge +6f4c44e4d0a68bca3838fb025c09cddfaaa08fe8, +[file 9566738](https://www.curseforge.com/minecraft/mc-mods/base-metals/files/9566738), +with unchanged 598D bytes. Full SHA-256 values are in gradle.properties. +Hosted builds still reject local-only pins, and remote Maven publication remains +disabled in this checkout. These guards are not bypassed by release acceptance. +Publication uses the default-branch dispatcher and its sealed CI artifacts, +not this checkout's disabled remote Maven tasks. + +Changing the Power source ref or API pin state changes the player manifest and +therefore the whole jar hash, even if all production classes and resources stay +identical. Keep the qualified 54662C9A artifact and receipts unchanged; qualify +and checksum the newly pinned artifact separately before publication. +Its exact hash must be handed over for a fresh presealed combined final-hash +restart/endurance campaign. Live publication requires that parent-owned gate +and baseSteam's verified public release. The 54662C9A receipts above stay bound +to their original jar and are not relabelled as new-hash runtime evidence. + +The released-pin player jar is +7128973D7A7529463E8F4328D0949F45641BD1560008A9925B09C74F9BE94F6D. +All 570 file entries match 54662C9A except META-INF/MANIFEST.MF; its only +changed attributes are API-Pin-State and basePower-Source-Ref. Sources and +Javadoc were byte-identical at the initial retarget. The new default-path release suite passes all +46 forced tasks, 114 unit tests and 25 native resource tests. Fresh actual +Eclipse compiler output passes 114 tests, with no ignored tests or assumptions. +An independent path-with-spaces build reproduces all three jars using the +already cold-qualified native engine. A fresh packaged witness passes all +29 Electric operations, complete JVM restart and independent stopped-save +audits before and after restart, using Electric 7128973D, Power C98D, Steam +F23D, Base Metals 598D and OreSpawn DE39. This does not replace the parent's +separate final-family restart/endurance and replay publication gate. + +The first hosted comparison exposed five JDK-generated Javadoc differences: +Windows SVG line endings and legal forwarding notices versus Linux's full +license texts. Javadoc now copies the complete legal texts from the selected +JDK's java.base module and normalizes those files and the generated SVGs to LF. +The release audit rejects noncanonical SVGs and incomplete or different legal +texts. This packaging correction affects only the Javadoc artifact, not the +player or sources. The earlier local 207BD6FE Javadoc remains preserved under +its original receipt; it is not relabelled as the cross-platform artifact. +The corrected Windows Javadoc matches the hosted Linux jar byte-for-byte: +7633A1BFCC86BE22F2814E5E6387289F722F67C484034CDDF366258A15D70845. diff --git a/gradle.properties b/gradle.properties index 0d823469..79bd9311 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,17 +3,21 @@ org.gradle.daemon=false org.gradle.configuration-cache=false org.gradle.caching=true org.gradle.parallel=false +org.gradle.workers.max=2 net.minecraftforge.gradle.merge-source-sets=false -minecraft_version=1.21.1 -minecraft_version_range=[1.21.1] -forge_version=52.1.0 -forge_installer_sha256=F1B620F2879AD6A5BBE15DABA4D8F81EAB9F5E08004967604960B98996BDEBC4 -forge_version_range=[52.1.0,53) -loader_version_range=[52,) +minecraft_version=1.21.11 +minecraft_version_range=[1.21.11] +forge_version=61.1.0 +forge_installer_sha256=8BD1724EAEAF26F51DACFB7FDC46D79E9B640705B70D5F0019ED38907145EB48 +forge_shim_sha256=09008DB9881E35E62669865F3B7420741EDB1A52BC59C67A5FA03D24C6C8E6E3 +forge_server_sha256=8D997159003977A22DB8E4EA6DAAB6CBB0E76F752A196A1821C74734A1CF71D9 +forge_universal_sha256=101041931319D508D94EF9ED6643CA4374EA3950237443301F7AA5A3B2631CC4 +forge_version_range=[61.1.0,62) +loader_version_range=[61,) mapping_channel=official -mapping_version=1.21.1 -mcp_version=20240808.132146 +mapping_version=1.21.11 +mcp_version=20251223.124241 loader_name=forge loader_code=1 @@ -26,32 +30,33 @@ curseforge_project_id=1783006 mod_id=baseelectric mod_name=baseElectric mod_license=GPL-3.0-only -mod_version=2.2.15.121011 +mod_version=2.2.16.121111 mod_group=zone.moddev.mc.baseelectric mod_authors=DrCyano mod_description=Electric-powered machines and infrastructure for basePower. cf_requirements=basepower,base-metals cf_optionals= -cf_versions=1.21.1 +cf_versions=1.21.11 -poweradvantage_version=2.4.14.121011 +poweradvantage_version=2.4.15.121111 poweradvantage_pin_state=MERGED_SOURCE poweradvantage_source_repository=MinecraftModDevelopmentMods/basePower -# Exact released basePower source and checksum-matching public jar. -poweradvantage_source_ref=8d9937b3c0c9ef28a231b90fc2ff6adfea1af733 -poweradvantage_public_file_id=9559143 -poweradvantage_deobf_sha256=F91A613EB5FAA218AAD2DC3C881DEC7B897A5EE874215282A439E34B915C1AE6 -poweradvantage_runtime_sha256=F91A613EB5FAA218AAD2DC3C881DEC7B897A5EE874215282A439E34B915C1AE6 +# Verified public basePower release; the ordinary native jar is also the dev jar. +poweradvantage_source_ref=9b0043483d79d3e575895f12aeb0dde7ef6c4890 +poweradvantage_public_file_id=9566998 +poweradvantage_deobf_sha256=C98D2CF163BE2480D9AFB0023BBD2D92D401AE0D50BEF73191235BF3F83774A7 +poweradvantage_runtime_sha256=C98D2CF163BE2480D9AFB0023BBD2D92D401AE0D50BEF73191235BF3F83774A7 -basemetals_version=3.1.2.121011 -basemetals_source_commit=327c197bcdd0bb5e883d844bb6a6c8791bc580b7 -basemetals_public_file_id=9559006 -basemetals_deobf_sha256=7C0B961A8D4991C9B69379518AAD700A71C1E4B2076CF5DEF292C58029408A07 -basemetals_runtime_sha256=7C0B961A8D4991C9B69379518AAD700A71C1E4B2076CF5DEF292C58029408A07 +basemetals_version=3.1.2.121111 +basemetals_source_commit=6f4c44e4d0a68bca3838fb025c09cddfaaa08fe8 +# Verified public release includes the shared non-cancelling migration hook. +basemetals_public_file_id=9566738 +basemetals_deobf_sha256=598D3FB0FF956EBCC67FE477A01CE393C75D0013AF0CE00A79E2072B63E9F2BA +basemetals_runtime_sha256=598D3FB0FF956EBCC67FE477A01CE393C75D0013AF0CE00A79E2072B63E9F2BA -orespawn_version=4.1.0.121011 -orespawn_source_commit=62c08169c71f4d4fd8f107289e63fd2a4c7c655c -orespawn_public_file_id=9189594 -orespawn_deobf_sha256=EB369B7D7CE6D6C453658347A420C2F0783B7F4D1AC7383C87176AC05192B5A0 -orespawn_runtime_sha256=EB369B7D7CE6D6C453658347A420C2F0783B7F4D1AC7383C87176AC05192B5A0 +orespawn_version=4.1.0.121111 +orespawn_source_commit=ecad75b24309a344f712d898d717c6a8823fc9f2 +orespawn_public_file_id=9268464 +orespawn_deobf_sha256=DE39929057288CEA110196C9E9D708E129B80BC360A2E53976337FFA6A84A67B +orespawn_runtime_sha256=DE39929057288CEA110196C9E9D708E129B80BC360A2E53976337FFA6A84A67B diff --git a/gradle/forge52-mavenizer.gradle b/gradle/forge52-mavenizer.gradle deleted file mode 100644 index aacd1ab2..00000000 --- a/gradle/forge52-mavenizer.gradle +++ /dev/null @@ -1,22 +0,0 @@ -import java.security.MessageDigest -import org.gradle.jvm.toolchain.JvmVendorSpec - -def fixture = file(providers.gradleProperty('forge52MavenizerJar').getOrElse( - '../../../../MinecraftMineralogy/OS1211/OreSpawn/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar')) -def expected = '019032A4A26ECB473D403EF017054D5892CE59A9904E8831B452287CD756397E' -if (!fixture.isFile()) { - throw new GradleException("Missing Forge 52 Mavenizer fixture: ${fixture}. Set -Pforge52MavenizerJar=.") -} -def actual = MessageDigest.getInstance('SHA-256').digest(fixture.bytes).encodeHex().toString().toUpperCase(Locale.ROOT) -if (actual != expected) { - throw new GradleException("Forge 52 Mavenizer fixture SHA-256 mismatch: expected ${expected}, got ${actual}") -} - -fgtools.configure('mavenizer') { - classpath.from(fixture) - mainClass.set('net.minecraftforge.mcmaven.cli.Main') - javaLauncher.set(javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(25) - vendor = JvmVendorSpec.ADOPTIUM - }) -} diff --git a/gradle/forge61-mavenizer.gradle b/gradle/forge61-mavenizer.gradle new file mode 100644 index 00000000..f587816d --- /dev/null +++ b/gradle/forge61-mavenizer.gradle @@ -0,0 +1,29 @@ +import java.security.MessageDigest +import org.gradle.jvm.toolchain.JvmVendorSpec + +def fixture = file(providers.gradleProperty('forge61MavenizerJar').getOrElse( + '../../../../MinecraftMineralogy/OS12111/OreSpawn/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar')) +def expected = 'B36CA046DB72E30F27BD38E02B4AE34274ADB51AE1D65BAF9E1D07763755682E' +if (!fixture.isFile()) { + throw new GradleException("Missing Forge 61 Mavenizer fixture: ${fixture}. Set -Pforge61MavenizerJar=.") +} +def actual = MessageDigest.getInstance('SHA-256').digest(fixture.bytes).encodeHex().toString().toUpperCase(Locale.ROOT) +if (actual != expected) { + throw new GradleException("Forge 61 Mavenizer fixture SHA-256 mismatch: expected ${expected}, got ${actual}") +} + +def rules = new File(fixture.parentFile, 'minecraft-source-compatibility.json') +def expectedRules = '88F2EE4C6B7C903EB1C7D693C0BEEFC0EFC601C1023FB197F7CBA187B1142DB7' +if (!rules.isFile() || MessageDigest.getInstance('SHA-256').digest(rules.bytes) + .encodeHex().toString().toUpperCase(Locale.ROOT) != expectedRules) { + throw new GradleException("Missing or mismatched Forge 61 Mavenizer rules: ${rules}") +} + +fgtools.configure('mavenizer') { + classpath.from(fixture) + mainClass.set('net.minecraftforge.mcmaven.cli.Main') + javaLauncher.set(javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(25) + vendor = JvmVendorSpec.ADOPTIUM + }) +} diff --git a/src/gametest/java/zone/moddev/mc/baseelectric/gametest/ElectricGameTests.java b/src/gametest/java/zone/moddev/mc/baseelectric/gametest/ElectricGameTests.java index e57d04b9..86bce497 100644 --- a/src/gametest/java/zone/moddev/mc/baseelectric/gametest/ElectricGameTests.java +++ b/src/gametest/java/zone/moddev/mc/baseelectric/gametest/ElectricGameTests.java @@ -5,7 +5,7 @@ import java.nio.file.Path; import net.minecraft.core.BlockPos; import net.minecraft.core.component.DataComponents; -import net.minecraft.gametest.framework.GameTest; +import net.minecraftforge.gametest.GameTest; import net.minecraft.gametest.framework.GameTestHelper; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; @@ -13,12 +13,12 @@ import net.minecraft.nbt.NbtUtils; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Recipe; import net.minecraftforge.gametest.GameTestDontPrefix; -import net.minecraftforge.gametest.GameTestHolder; +import net.minecraftforge.gametest.GameTestNamespace; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.init.Blocks; import zone.moddev.mc.baseelectric.init.Items; @@ -27,25 +27,41 @@ import zone.moddev.mc.baseelectric.machines.ElectricDrillTileEntity; import zone.moddev.mc.baseelectric.machines.LaserTurretTileEntity; -@GameTestHolder(value = ElectricAdvantage.MODID, namespace = ElectricAdvantage.MODID) +@GameTestNamespace(ElectricAdvantage.MODID) @GameTestDontPrefix +@net.minecraftforge.fml.common.Mod.EventBusSubscriber(modid = ElectricAdvantage.MODID, + bus = net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.MOD) public final class ElectricGameTests { private ElectricGameTests() {} + @net.minecraftforge.eventbus.api.listener.SubscribeEvent + public static void registerFunctions(net.minecraftforge.registries.RegisterEvent event) { + event.register(net.minecraft.core.registries.Registries.TEST_FUNCTION, registry -> { + registry.register(Identifier.parse("baseelectric:drillupgradesandtransferslegacybattery"), + ElectricGameTests::drillUpgradesAndTransfersLegacyBattery); + registry.register(Identifier.parse("baseelectric:recipeavailabilitydoesnotremovediscovery"), + ElectricGameTests::recipeAvailabilityDoesNotRemoveDiscovery); + registry.register(Identifier.parse("baseelectric:siliconandsolderresolverealmaterialtags"), + ElectricGameTests::siliconAndSolderResolveRealMaterialTags); + registry.register(Identifier.parse("baseelectric:turretusesnativeupdatepacket"), + ElectricGameTests::turretUsesNativeUpdatePacket); + }); + } + public static void main(String[] args) throws Exception { Path output = Path.of(args[1]); Files.createDirectories(output.getParent()); NbtIo.writeCompressed(NbtUtils.snbtToStructure(Files.readString(Path.of(args[0]))), output); } - @GameTest(batch = ElectricAdvantage.MODID, template = "empty") + @GameTest(name = "drillupgradesandtransferslegacybattery", structure = "empty") public static void drillUpgradesAndTransfersLegacyBattery(GameTestHelper helper) { BlockPos source = new BlockPos(1, 1, 1); BlockPos destination = source.east(); helper.setBlock(source, Blocks.laser_drill); helper.setBlock(destination, Blocks.laser_drill); - var drill = (ElectricDrillTileEntity) helper.getBlockEntity(source); - var relocated = (ElectricDrillTileEntity) helper.getBlockEntity(destination); + var drill = helper.getBlockEntity(source, ElectricDrillTileEntity.class); + var relocated = helper.getBlockEntity(destination, ElectricDrillTileEntity.class); var registries = helper.getLevel().registryAccess(); CompoundTag batteryData = new CompoundTag(); batteryData.putFloat("energy", 0.0F); @@ -59,51 +75,85 @@ public static void drillUpgradesAndTransfersLegacyBattery(GameTestHelper helper) slots.add(oldStack); CompoundTag oldInventory = new CompoundTag(); oldInventory.put("Items", slots); - drill.loadWithComponents(oldInventory, registries); + load(drill, oldInventory, registries); ItemStack stack = drill.getOutputSlot(0); var battery = (BatteryItem) Items.lead_acid_battery; helper.assertTrue(stack != null && stack.is(battery), "The legacy slot did not load as a battery"); helper.assertTrue(battery.getEnergy(stack) == 0.0F, "The depleted battery became charged"); helper.assertTrue(battery.addEnergy(stack, 25.0F, Power.ELECTRIC_POWER) == 25.0F, "The loaded battery cannot receive charge"); - relocated.loadWithComponents(drill.saveWithoutMetadata(registries), registries); + load(relocated, drill.saveWithoutMetadata(registries), registries); ItemStack moved = relocated.getOutputSlot(0); helper.assertTrue(moved != null && ItemStack.matches(stack, moved), "Drill transfer did not preserve the battery components"); - helper.assertTrue("old-drill-slot".equals(moved.get(DataComponents.CUSTOM_DATA).copyTag().getString("marker")), + helper.assertTrue("old-drill-slot".equals(moved.get(DataComponents.CUSTOM_DATA).copyTag().getString("marker").orElseThrow()), "Charging the battery erased unrelated data"); helper.assertTrue(relocated.getBlockPos().equals(helper.absolutePos(destination)), "Drill transfer changed the destination position"); helper.succeed(); } - @GameTest(batch = ElectricAdvantage.MODID, template = "empty") + @GameTest(name = "recipeavailabilitydoesnotremovediscovery", structure = "empty") public static void recipeAvailabilityDoesNotRemoveDiscovery(GameTestHelper helper) { var server = helper.getLevel().getServer(); - var advancement = ResourceLocation.fromNamespaceAndPath(ElectricAdvantage.MODID, "recipes/alkaline_battery"); + var advancement = Identifier.fromNamespaceAndPath(ElectricAdvantage.MODID, "recipes/alkaline_battery"); helper.assertTrue(server.getAdvancements().get(advancement) != null, "A material-gated recipe lost its discovery advancement"); int checked = 0; var registries = helper.getLevel().registryAccess(); + var entries = new java.util.ArrayList(); for (var holder : server.getRecipeManager().getRecipes()) { - if (!holder.id().getNamespace().equals(ElectricAdvantage.MODID)) continue; - RegistryFriendlyByteBuf buffer = new RegistryFriendlyByteBuf(Unpooled.buffer(), registries); - try { - Recipe.STREAM_CODEC.encode(buffer, holder.value()); - var decoded = Recipe.STREAM_CODEC.decode(buffer); - helper.assertTrue(decoded.getSerializer() == holder.value().getSerializer() - && ItemStack.matches(decoded.getResultItem(registries), holder.value().getResultItem(registries)), - "Electric recipe changed over the native network codec: " + holder.id()); - } finally { - buffer.release(); - } + if (!holder.id().identifier().getNamespace().equals(ElectricAdvantage.MODID)) continue; + int before = entries.size(); + server.getRecipeManager().listDisplaysForRecipe(holder.id(), display -> entries.add( + new net.minecraft.network.protocol.game.ClientboundRecipeBookAddPacket.Entry( + display, holder.value().showNotification(), true))); + helper.assertTrue(entries.size() - before == holder.value().display().size(), + "Electric recipe lost its native client displays: " + holder.id()); checked++; } helper.assertTrue(checked > 0, "No Electric recipes were present for the network check"); + helper.assertTrue(!entries.isEmpty(), "No Electric recipe-book entries were present"); + var packet = new net.minecraft.network.protocol.game.ClientboundRecipeBookAddPacket(entries, true); + RegistryFriendlyByteBuf buffer = new RegistryFriendlyByteBuf(Unpooled.buffer(), registries); + RegistryFriendlyByteBuf roundTrip = new RegistryFriendlyByteBuf(Unpooled.buffer(), registries); + try { + net.minecraft.network.protocol.game.ClientboundRecipeBookAddPacket.STREAM_CODEC.encode(buffer, packet); + byte[] originalBytes = io.netty.buffer.ByteBufUtil.getBytes(buffer); + var decoded = net.minecraft.network.protocol.game.ClientboundRecipeBookAddPacket.STREAM_CODEC.decode(buffer); + net.minecraft.network.protocol.game.ClientboundRecipeBookAddPacket.STREAM_CODEC.encode(roundTrip, decoded); + helper.assertTrue(decoded.replace() && decoded.entries().size() == entries.size() + && java.util.Arrays.equals(originalBytes, io.netty.buffer.ByteBufUtil.getBytes(roundTrip)), + "Electric recipe displays changed over the actual native recipe-book packet"); + } finally { + buffer.release(); + roundTrip.release(); + } + assertEveryPackagedRecipeUsesTheNativeCodec(helper); helper.succeed(); } - @GameTest(batch = ElectricAdvantage.MODID, template = "empty") + private static void assertEveryPackagedRecipeUsesTheNativeCodec(GameTestHelper helper) { + var resources = helper.getLevel().getServer().getResourceManager().listResources("recipe", + id -> id.getNamespace().equals(ElectricAdvantage.MODID) && id.getPath().endsWith(".json")); + helper.assertTrue(resources.size() == 58, "Expected all 58 packaged Electric recipes, found " + resources.size()); + var ops = helper.getLevel().registryAccess().createSerializationContext(com.mojang.serialization.JsonOps.INSTANCE); + for (var entry : resources.entrySet()) { + try (var reader = entry.getValue().openAsReader()) { + var json = com.google.gson.JsonParser.parseReader(reader); + var decoded = Recipe.CODEC.parse(ops, json).getOrThrow(); + var encoded = Recipe.CODEC.encodeStart(ops, decoded).getOrThrow(); + var again = Recipe.CODEC.parse(ops, encoded).getOrThrow(); + helper.assertTrue(decoded.getSerializer() == again.getSerializer() + && encoded.equals(Recipe.CODEC.encodeStart(ops, again).getOrThrow()), + "Packaged recipe changed over its native codec: " + entry.getKey()); + } catch (Exception failure) { + throw new AssertionError("Native recipe codec rejected " + entry.getKey(), failure); + } + } + } + + @GameTest(name = "siliconandsolderresolverealmaterialtags", structure = "empty") public static void siliconAndSolderResolveRealMaterialTags(GameTestHelper helper) { assertLoadedRecipe(helper, "silicon_blend", Items.silicon_blend, 1); assertLoadedRecipe(helper, "silicon_ingot_from_blend", Items.silicon_ingot, 1); @@ -114,22 +164,27 @@ public static void siliconAndSolderResolveRealMaterialTags(GameTestHelper helper } private static void assertLoadedRecipe(GameTestHelper helper, String path, Item item, int count) { - var id = ResourceLocation.fromNamespaceAndPath(ElectricAdvantage.MODID, path); + var id = Identifier.fromNamespaceAndPath(ElectricAdvantage.MODID, path); var level = helper.getLevel(); - var holder = level.getRecipeManager().byKey(id); + var holder = level.recipeAccess().byKey(net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.RECIPE, id)); helper.assertTrue(holder.isPresent(), "Recipe was gated despite valid materials: " + id); var recipe = holder.orElseThrow().value(); - helper.assertTrue(recipe.getIngredients().stream().allMatch(ingredient -> ingredient.getItems().length > 0), + helper.assertTrue(!recipe.placementInfo().ingredients().isEmpty() + && recipe.placementInfo().ingredients().stream().allMatch(ingredient -> !ingredient.isEmpty()), "Recipe loaded with an empty ingredient: " + id); - helper.assertTrue(ItemStack.matches(new ItemStack(item, count), recipe.getResultItem(level.registryAccess())), + var encoded = Recipe.CODEC.encodeStart(level.registryAccess().createSerializationContext( + com.mojang.serialization.JsonOps.INSTANCE), recipe).getOrThrow().getAsJsonObject(); + var result = ItemStack.CODEC.parse(level.registryAccess().createSerializationContext( + com.mojang.serialization.JsonOps.INSTANCE), encoded.get("result")).getOrThrow(); + helper.assertTrue(ItemStack.matches(new ItemStack(item, count), result), "Unexpected output for " + id); } - @GameTest(batch = ElectricAdvantage.MODID, template = "empty") + @GameTest(name = "turretusesnativeupdatepacket", structure = "empty") public static void turretUsesNativeUpdatePacket(GameTestHelper helper) { BlockPos relative = new BlockPos(1, 1, 1); helper.setBlock(relative, Blocks.laser_turret); - var turret = (LaserTurretTileEntity) helper.getBlockEntity(relative); + var turret = helper.getBlockEntity(relative, LaserTurretTileEntity.class); var packet = turret.getUpdatePacket(); RegistryFriendlyByteBuf buffer = new RegistryFriendlyByteBuf(Unpooled.buffer(), helper.getLevel().registryAccess()); try { @@ -144,4 +199,11 @@ public static void turretUsesNativeUpdatePacket(GameTestHelper helper) { } helper.succeed(); } + + private static void load(net.minecraft.world.level.block.entity.BlockEntity tile, CompoundTag data, + net.minecraft.core.HolderLookup.Provider registries) { + try (var problems = new net.minecraft.util.ProblemReporter.ScopedCollector(org.slf4j.LoggerFactory.getLogger("baseelectric-gametest"))) { + tile.loadWithComponents(net.minecraft.world.level.storage.TagValueInput.create(problems, registries, data)); + } + } } diff --git a/src/gametest/resources/data/baseelectric/test_instance/drillupgradesandtransferslegacybattery.json b/src/gametest/resources/data/baseelectric/test_instance/drillupgradesandtransferslegacybattery.json new file mode 100644 index 00000000..81d494d0 --- /dev/null +++ b/src/gametest/resources/data/baseelectric/test_instance/drillupgradesandtransferslegacybattery.json @@ -0,0 +1,7 @@ +{ + "type": "minecraft:function", + "function": "baseelectric:drillupgradesandtransferslegacybattery", + "environment": "minecraft:default", + "structure": "baseelectric:empty", + "max_ticks": 100 +} diff --git a/src/gametest/resources/data/baseelectric/test_instance/recipeavailabilitydoesnotremovediscovery.json b/src/gametest/resources/data/baseelectric/test_instance/recipeavailabilitydoesnotremovediscovery.json new file mode 100644 index 00000000..ddbbeb71 --- /dev/null +++ b/src/gametest/resources/data/baseelectric/test_instance/recipeavailabilitydoesnotremovediscovery.json @@ -0,0 +1,7 @@ +{ + "type": "minecraft:function", + "function": "baseelectric:recipeavailabilitydoesnotremovediscovery", + "environment": "minecraft:default", + "structure": "baseelectric:empty", + "max_ticks": 100 +} diff --git a/src/gametest/resources/data/baseelectric/test_instance/siliconandsolderresolverealmaterialtags.json b/src/gametest/resources/data/baseelectric/test_instance/siliconandsolderresolverealmaterialtags.json new file mode 100644 index 00000000..61b887a1 --- /dev/null +++ b/src/gametest/resources/data/baseelectric/test_instance/siliconandsolderresolverealmaterialtags.json @@ -0,0 +1,7 @@ +{ + "type": "minecraft:function", + "function": "baseelectric:siliconandsolderresolverealmaterialtags", + "environment": "minecraft:default", + "structure": "baseelectric:empty", + "max_ticks": 100 +} diff --git a/src/gametest/resources/data/baseelectric/test_instance/turretusesnativeupdatepacket.json b/src/gametest/resources/data/baseelectric/test_instance/turretusesnativeupdatepacket.json new file mode 100644 index 00000000..e7e6c458 --- /dev/null +++ b/src/gametest/resources/data/baseelectric/test_instance/turretusesnativeupdatepacket.json @@ -0,0 +1,7 @@ +{ + "type": "minecraft:function", + "function": "baseelectric:turretusesnativeupdatepacket", + "environment": "minecraft:default", + "structure": "baseelectric:empty", + "max_ticks": 100 +} diff --git a/src/main/java/zone/moddev/mc/baseelectric/ElectricAdvantage.java b/src/main/java/zone/moddev/mc/baseelectric/ElectricAdvantage.java index f5f05220..479774ce 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/ElectricAdvantage.java +++ b/src/main/java/zone/moddev/mc/baseelectric/ElectricAdvantage.java @@ -25,13 +25,13 @@ import zone.moddev.mc.baseelectric.recipe.RecipeConditions; import zone.moddev.mc.baseelectric.migration.ElectricLegacyMigrations; -/** Forge 1.21.1 entry point for baseElectric. */ +/** Forge 1.21.11 entry point for baseElectric. */ @Mod(ElectricAdvantage.MODID) public final class ElectricAdvantage { public static final String MODID = "baseelectric"; public static final String LEGACY_MODID = "electricadvantage"; public static final String NAME = "baseElectric"; - public static final String VERSION = "2.2.15.121011"; + public static final String VERSION = "2.2.16.121111"; public static final Logger LOGGER = LogManager.getLogger(MODID); public static ElectricAdvantage INSTANCE; @@ -41,14 +41,18 @@ public final class ElectricAdvantage { public ElectricAdvantage(FMLJavaModLoadingContext context) { INSTANCE = this; ElectricLegacyMigrations.register(); - RecipeConditions.register(context.getModEventBus()); + var bus = context.getModBusGroup(); + RecipeConditions.register(bus); migrateLegacyOreSpawnConfiguration(); migrateLegacyConfiguration(); context.registerConfig(ModConfig.Type.COMMON, ElectricAdvantageConfig.SPEC); - context.getModEventBus().addListener(ElectricAdvantageConfig::onConfigLoading); - context.getModEventBus().addListener(this::commonSetup); - context.getModEventBus().addListener(this::enqueueInterModCommunication); + net.minecraftforge.fml.event.config.ModConfigEvent.Loading.getBus(bus) + .addListener(ElectricAdvantageConfig::onConfigLoading); + net.minecraftforge.fml.event.config.ModConfigEvent.Reloading.getBus(bus) + .addListener(ElectricAdvantageConfig::onConfigReloading); + FMLCommonSetupEvent.getBus(bus).addListener(this::commonSetup); + InterModEnqueueEvent.getBus(bus).addListener(this::enqueueInterModCommunication); } private static void migrateLegacyOreSpawnConfiguration() { diff --git a/src/main/java/zone/moddev/mc/baseelectric/blocks/ElectricConduitBlock.java b/src/main/java/zone/moddev/mc/baseelectric/blocks/ElectricConduitBlock.java index 520060d4..eff83bc9 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/blocks/ElectricConduitBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/blocks/ElectricConduitBlock.java @@ -7,7 +7,12 @@ public class ElectricConduitBlock extends cyano.poweradvantage.api.simple.BlockSimplePowerConduit{ public ElectricConduitBlock() { - super(Properties.of().mapColor(MapColor.STONE).pushReaction(PushReaction.BLOCK) + this("electric_conduit"); + } + + protected ElectricConduitBlock(String id) { + super(Properties.of().setId(zone.moddev.mc.baseelectric.util.RegistryIds.block(id)) + .mapColor(MapColor.STONE).pushReaction(PushReaction.BLOCK) .forceSolidOn().strength(0.75f), 2f/16f, Power.ELECTRIC_POWER); } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/blocks/ElectricScaffoldBlock.java b/src/main/java/zone/moddev/mc/baseelectric/blocks/ElectricScaffoldBlock.java index 44f245bf..95269b02 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/blocks/ElectricScaffoldBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/blocks/ElectricScaffoldBlock.java @@ -14,7 +14,8 @@ /** Full-block electric track/scaffold with conduit behavior. */ public class ElectricScaffoldBlock extends BlockSimplePowerConduit { public ElectricScaffoldBlock() { - super(Properties.of().mapColor(MapColor.STONE).pushReaction(PushReaction.BLOCK) + super(Properties.of().setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("electric_track")) + .mapColor(MapColor.STONE).pushReaction(PushReaction.BLOCK) .forceSolidOn().strength(0.75F).noOcclusion() .isRedstoneConductor((state, world, pos) -> false), 2.0F / 16.0F, Power.ELECTRIC_POWER); diff --git a/src/main/java/zone/moddev/mc/baseelectric/blocks/Ore.java b/src/main/java/zone/moddev/mc/baseelectric/blocks/Ore.java index 76a48574..cf774559 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/blocks/Ore.java +++ b/src/main/java/zone/moddev/mc/baseelectric/blocks/Ore.java @@ -35,14 +35,16 @@ private static Supplier fixedDrop(ItemStack oreDrop) { } private Ore(Supplier drop, int pickLevel, int variation) { - super(Properties.of().mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE) + super(Properties.of().setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("sulfur_ore")) + .mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE) .strength(1.5F + pickLevel, 5.0F * (1 + pickLevel))); this.drop = drop; dropRange = variation + 1; } public Ore(int pickLevel) { - super(Properties.of().mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE) + super(Properties.of().setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("li_ore")) + .mapColor(MapColor.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE) .strength(1.5F + pickLevel, 5.0F * (1 + pickLevel))); drop = () -> ItemStack.EMPTY; dropRange = 0; diff --git a/src/main/java/zone/moddev/mc/baseelectric/blocks/PumpPipeBlock.java b/src/main/java/zone/moddev/mc/baseelectric/blocks/PumpPipeBlock.java index ddbf0a66..51892f80 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/blocks/PumpPipeBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/blocks/PumpPipeBlock.java @@ -15,25 +15,26 @@ public class PumpPipeBlock extends Block { private static final VoxelShape SHAPE = Shapes.box(0.25D, 0.0D, 0.25D, 0.75D, 1.0D, 0.75D); public PumpPipeBlock() { - super(Properties.of().mapColor(MapColor.METAL).forceSolidOn().strength(5.0F, 10.0F) + super(Properties.of().setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("pump_pipe_electric")) + .mapColor(MapColor.METAL).forceSolidOn().strength(5.0F, 10.0F) .dynamicShape().noOcclusion().isRedstoneConductor((state, world, pos) -> false).noLootTable()); } @Override public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { return SHAPE; } @Override public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { return SHAPE; } @Override - public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean moving) { - if (state.getBlock() != newState.getBlock()) destroyBelow(world, pos); - super.onRemove(state, world, pos, newState, moving); + public void affectNeighborsAfterRemoval(BlockState state, net.minecraft.server.level.ServerLevel world, BlockPos pos, boolean moving) { + destroyBelow(world, pos); + super.affectNeighborsAfterRemoval(state, world, pos, moving); } - @Override public void wasExploded(Level world, BlockPos pos, Explosion explosion) { + @Override public void wasExploded(net.minecraft.server.level.ServerLevel world, BlockPos pos, Explosion explosion) { destroyBelow(world, pos); super.wasExploded(world, pos, explosion); } private void destroyBelow(Level world, BlockPos pos) { - if (world.isClientSide) return; + if (world.isClientSide()) return; BlockPos cursor = pos.below(); while (cursor.getY() > 0 && world.getBlockState(cursor).getBlock() == this) { world.setBlock(cursor, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), 3); diff --git a/src/main/java/zone/moddev/mc/baseelectric/compat/BaseMetalsCompat.java b/src/main/java/zone/moddev/mc/baseelectric/compat/BaseMetalsCompat.java index 438f5f43..cabdac37 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/compat/BaseMetalsCompat.java +++ b/src/main/java/zone/moddev/mc/baseelectric/compat/BaseMetalsCompat.java @@ -6,7 +6,7 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.RecipeHolder; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.world.level.Level; import net.minecraftforge.fml.ModList; import net.minecraftforge.registries.ForgeRegistries; @@ -32,11 +32,11 @@ public static boolean hasCrusherRecipe(Level world, ItemStack input) { public static ItemStack getCrusherRecipeOutput(Level world, ItemStack input) { if (world == null || input == null || input.isEmpty()) return null; - if (isLoaded()) { + if (isLoaded() && world instanceof net.minecraft.server.level.ServerLevel server) { SingleRecipeInput inventory = new SingleRecipeInput(input.copy()); - for (RecipeHolder holder : world.getRecipeManager().getRecipes()) { + for (RecipeHolder holder : server.recipeAccess().getRecipes()) { if (holder.value() instanceof CrushingRecipe candidate && candidate.matches(inventory, world)) { - return candidate.getResultItem(world.registryAccess()).copy(); + return candidate.assemble(inventory, world.registryAccess()); } } } @@ -75,7 +75,7 @@ private static ItemStack getVanillaCrusherOutput(ItemStack input) { } private static ItemStack stack(String id, int count) { - Item item = ForgeRegistries.ITEMS.getValue(ResourceLocation.parse(id)); + Item item = ForgeRegistries.ITEMS.getValue(Identifier.parse(id)); return item == null ? null : new ItemStack(item, count); } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/config/ElectricAdvantageConfig.java b/src/main/java/zone/moddev/mc/baseelectric/config/ElectricAdvantageConfig.java index 306cd7b3..cc7a0aae 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/config/ElectricAdvantageConfig.java +++ b/src/main/java/zone/moddev/mc/baseelectric/config/ElectricAdvantageConfig.java @@ -32,6 +32,14 @@ public final class ElectricAdvantageConfig { private ElectricAdvantageConfig() {} public static void onConfigLoading(ModConfigEvent.Loading event) { + update(event); + } + + public static void onConfigReloading(ModConfigEvent.Reloading event) { + update(event); + } + + private static void update(ModConfigEvent event) { if (event.getConfig().getSpec() != SPEC) return; loaded = true; apply(); diff --git a/src/main/java/zone/moddev/mc/baseelectric/entities/HydroturbineEntity.java b/src/main/java/zone/moddev/mc/baseelectric/entities/HydroturbineEntity.java index e3447f93..e2c3f527 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/entities/HydroturbineEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/entities/HydroturbineEntity.java @@ -58,16 +58,16 @@ public boolean isPushedByFluid() { @Override public void tick(){ super.tick(); - FluidState fluidState = this.getCommandSenderWorld().getFluidState(blockPosition()); + FluidState fluidState = this.level().getFluidState(blockPosition()); Vec3 directionVector; if(!fluidState.isEmpty()){ - directionVector = fluidState.getFlow(getCommandSenderWorld(), blockPosition()); + directionVector = fluidState.getFlow(level(), blockPosition()); isSpinning = !(directionVector.x == 0 && directionVector.z == 0); } else { isSpinning = false; directionVector = new Vec3(0,0,0); } - if(this.getCommandSenderWorld().isClientSide){ + if(this.level().isClientSide()){ // client-side only if(isSpinning){ rotation += DEGREES_PER_TICK; @@ -78,8 +78,8 @@ public void tick(){ } else { // server-side only if((parent == null || parent.isRemoved()) && parentCoord != null){ - if(!this.getCommandSenderWorld().hasChunkAt(parentCoord)) return; - parent = this.getCommandSenderWorld().getBlockEntity(parentCoord); + if(!this.level().hasChunkAt(parentCoord)) return; + parent = this.level().getBlockEntity(parentCoord); } if(parent == null || parent.isRemoved()){ this.discard(); @@ -90,29 +90,45 @@ public void tick(){ } generator.setActive(isSpinning); } - if(isSpinning && getCommandSenderWorld().getGameTime() % 8 == roffset){ + if(isSpinning && level().getGameTime() % 8 == roffset){ // slice-n-dice unfortunate souls caught in the blades - List victims = getCommandSenderWorld().getEntitiesOfClass(LivingEntity.class, this.getBoundingBox()); + List victims = level().getEntitiesOfClass(LivingEntity.class, this.getBoundingBox()); for(Entity e : victims){ - e.hurt(Power.damageSource(getCommandSenderWorld(), Power.PROPELLER_DAMAGE), PROPELLER_DAMAGE); + e.hurtServer((net.minecraft.server.level.ServerLevel) level(), + Power.damageSource(level(), Power.PROPELLER_DAMAGE), PROPELLER_DAMAGE); } } } } @Override + protected void readAdditionalSaveData(net.minecraft.world.level.storage.ValueInput input) { + readAdditionalSaveData(input.read(zone.moddev.mc.baseelectric.util.LegacyNbt.ROOT).orElseGet(CompoundTag::new)); + } + + @Override + protected void addAdditionalSaveData(net.minecraft.world.level.storage.ValueOutput output) { + CompoundTag root = new CompoundTag(); + addAdditionalSaveData(root); + output.store(zone.moddev.mc.baseelectric.util.LegacyNbt.ROOT, root); + } + + @Override + public boolean hurtServer(net.minecraft.server.level.ServerLevel level, net.minecraft.world.damagesource.DamageSource source, float amount) { + return false; + } + protected void readAdditionalSaveData(CompoundTag root) { parent = null; parentCoord = null; - if(root.contains("parentPos", 11)){ - int[] coords = root.getIntArray("parentPos"); + if((root.get("parentPos") instanceof net.minecraft.nbt.IntArrayTag)){ + int[] coords = root.getIntArray("parentPos").orElseGet(() -> new int[0]); if(coords.length >= 3){ parentCoord = new BlockPos(coords[0],coords[1],coords[2]); } } } - @Override protected void addAdditionalSaveData(CompoundTag root) { BlockPos p = parent != null ? parent.getBlockPos() : parentCoord; if(p != null){ diff --git a/src/main/java/zone/moddev/mc/baseelectric/graphics/BufferedQuads.java b/src/main/java/zone/moddev/mc/baseelectric/graphics/BufferedQuads.java index acff1ea3..4df6a86f 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/graphics/BufferedQuads.java +++ b/src/main/java/zone/moddev/mc/baseelectric/graphics/BufferedQuads.java @@ -13,7 +13,11 @@ final class BufferedQuads { private int count; BufferedQuads(PoseStack matrices, VertexConsumer buffer, int light, int overlay) { - this.transform = matrices.last(); + this(matrices.last(), buffer, light, overlay); + } + + BufferedQuads(PoseStack.Pose transform, VertexConsumer buffer, int light, int overlay) { + this.transform = transform; this.buffer = buffer; this.light = light; this.overlay = overlay; diff --git a/src/main/java/zone/moddev/mc/baseelectric/graphics/ClientRegistration.java b/src/main/java/zone/moddev/mc/baseelectric/graphics/ClientRegistration.java index 5f3c7fa3..89c41f0b 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/graphics/ClientRegistration.java +++ b/src/main/java/zone/moddev/mc/baseelectric/graphics/ClientRegistration.java @@ -2,17 +2,13 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.EntityRenderersEvent; -import net.minecraftforge.client.event.RegisterShadersEvent; -import net.minecraft.client.renderer.ShaderInstance; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import java.io.IOException; -import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.eventbus.api.listener.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.init.Entities; /** Client-only renderer registration. */ -@Mod.EventBusSubscriber(modid = ElectricAdvantage.MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +@Mod.EventBusSubscriber(modid = ElectricAdvantage.MODID, value = Dist.CLIENT) public final class ClientRegistration { private ClientRegistration() {} @@ -23,9 +19,4 @@ public static void registerRenderers(EntityRenderersEvent.RegisterRenderers even event.registerEntityRenderer(Entities.HYDROTURBINE, HydroturbineRenderer::new); } - @SubscribeEvent - public static void registerShaders(RegisterShadersEvent event) throws IOException { - event.registerShader(new ShaderInstance(event.getResourceProvider(), ElectricRenderTypes.UNSHADED, - DefaultVertexFormat.NEW_ENTITY), ElectricRenderTypes::setUnshadedShader); - } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/graphics/ElectricRenderTypes.java b/src/main/java/zone/moddev/mc/baseelectric/graphics/ElectricRenderTypes.java index 2b2e9280..1a84168b 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/graphics/ElectricRenderTypes.java +++ b/src/main/java/zone/moddev/mc/baseelectric/graphics/ElectricRenderTypes.java @@ -1,30 +1,34 @@ package zone.moddev.mc.baseelectric.graphics; -import net.minecraft.client.renderer.RenderStateShard; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.ShaderInstance; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.VertexFormat; -import net.minecraft.resources.ResourceLocation; +import com.mojang.blaze3d.pipeline.BlendFunction; +import com.mojang.blaze3d.pipeline.RenderPipeline; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.client.renderer.rendertype.RenderSetup; +import net.minecraft.client.renderer.rendertype.RenderType; +import net.minecraft.resources.Identifier; -/** Scoped render state replaces the old global lighting/blending mutations. */ -final class ElectricRenderTypes extends RenderStateShard { - static final ResourceLocation UNSHADED = ResourceLocation.fromNamespaceAndPath(zone.moddev.mc.baseelectric.ElectricAdvantage.MODID, "unshaded"); - private static ShaderInstance unshadedShader; - private ElectricRenderTypes() { - super("baseelectric", () -> {}, () -> {}); - } +/** Native entity shaders retain overlay, lightmap and fog without diffuse shading. */ +final class ElectricRenderTypes { + private static final RenderPipeline OPAQUE = pipeline(false); + private static final RenderPipeline TRANSLUCENT = pipeline(true); + + private ElectricRenderTypes() {} - static void setUnshadedShader(ShaderInstance shader) { - unshadedShader = shader; + private static RenderPipeline pipeline(boolean translucent) { + var builder = RenderPipeline.builder(RenderPipelines.ENTITY_SNIPPET) + .withLocation(Identifier.fromNamespaceAndPath("baseelectric", + translucent ? "pipeline/unshaded_translucent" : "pipeline/unshaded")) + .withShaderDefine("NO_CARDINAL_LIGHTING").withSampler("Sampler1").withCull(false); + if (translucent) builder.withBlend(BlendFunction.TRANSLUCENT); + RenderPipeline pipeline = builder.build(); + RenderPipelines.PIPELINES_BY_LOCATION.put(pipeline.getLocation(), pipeline); + return pipeline; } - static RenderType unshaded(ResourceLocation texture, boolean translucent) { - return RenderType.create("baseelectric_unshaded", DefaultVertexFormat.NEW_ENTITY, - VertexFormat.Mode.QUADS, 256, false, translucent, RenderType.CompositeState.builder() - .setTextureState(new TextureStateShard(texture, false, false)) - .setTransparencyState(translucent ? TRANSLUCENT_TRANSPARENCY : NO_TRANSPARENCY) - .setShaderState(new ShaderStateShard(() -> unshadedShader)).setCullState(NO_CULL) - .setLightmapState(LIGHTMAP).setOverlayState(OVERLAY).createCompositeState(false)); + static RenderType unshaded(Identifier texture, boolean translucent) { + var setup = RenderSetup.builder(translucent ? TRANSLUCENT : OPAQUE) + .withTexture("Sampler0", texture).useLightmap().useOverlay().bufferSize(256); + if (translucent) setup.sortOnUpload(); + return RenderType.create("baseelectric_unshaded", setup.createRenderSetup()); } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/graphics/HydroturbineRenderer.java b/src/main/java/zone/moddev/mc/baseelectric/graphics/HydroturbineRenderer.java index efec804f..f6268709 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/graphics/HydroturbineRenderer.java +++ b/src/main/java/zone/moddev/mc/baseelectric/graphics/HydroturbineRenderer.java @@ -4,19 +4,18 @@ import zone.moddev.mc.baseelectric.entities.HydroturbineEntity; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.rendertype.RenderTypes; +import net.minecraft.client.renderer.SubmitNodeCollector; +import net.minecraft.client.renderer.entity.state.EntityRenderState; +import net.minecraft.client.renderer.state.CameraRenderState; import com.mojang.math.Axis; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRendererProvider; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.util.Mth; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -@OnlyIn(Dist.CLIENT) -public class HydroturbineRenderer extends EntityRenderer{ - private static final ResourceLocation texture = ResourceLocation.parse(ElectricAdvantage.MODID+":textures/entity/hydroturbine.png"); +public class HydroturbineRenderer extends EntityRenderer{ + private static final Identifier texture = Identifier.parse(ElectricAdvantage.MODID+":textures/entity/hydroturbine.png"); private static final float DEGREES_TO_RADIANS = (float)(Math.PI / 180); @@ -24,13 +23,35 @@ public HydroturbineRenderer(final EntityRendererProvider.Context rm) { super(rm); } - @Override - public void render(final HydroturbineEntity entity, final float entityYaw, final float partialTick, - final PoseStack matrices, final MultiBufferSource buffers, final int packedLight) { + public static final class State extends EntityRenderState { + float yaw; + float rotation; + } + + @Override public State createRenderState() { return new State(); } + + @Override public void extractRenderState(HydroturbineEntity entity, State state, float partialTick) { + super.extractRenderState(entity, state, partialTick); + state.yaw = entity.getYRot(); + state.rotation = entity.rotation + (entity.isSpinning ? HydroturbineEntity.DEGREES_PER_TICK * partialTick : 0); + } + + @Override public void submit(State state, PoseStack matrices, SubmitNodeCollector collector, CameraRenderState camera) { + matrices.pushPose(); + matrices.translate(0f, 0.5f, 0f); + matrices.mulPose(Axis.YP.rotationDegrees(state.yaw)); + float rotation = state.rotation; + int light = state.lightCoords; + collector.submitCustomGeometry(matrices, RenderTypes.entitySolid(texture), + (pose, vertices) -> draw(rotation, pose, vertices, light)); + matrices.popPose(); + super.submit(state, matrices, collector, camera); + } + + private static void draw(float rotation, PoseStack.Pose pose, + com.mojang.blaze3d.vertex.VertexConsumer vertices, int packedLight) { { final float pixel = 1.0f / 16; - HydroturbineEntity e = (HydroturbineEntity)entity; - matrices.pushPose(); final float topHeight = 0.5f; final float bottomHeight = 0.375f-0.5f; final float radius = pixel; @@ -39,10 +60,7 @@ public void render(final HydroturbineEntity entity, final float entityYaw, final final float shaftMaxU = 0.5f+2*pixel; final float shaftMaxV = 1.0f; - matrices.translate(0f, 0.5f, 0f); - matrices.mulPose(Axis.YP.rotationDegrees(e.getYRot())); - final BufferedQuads worldRenderer = new BufferedQuads(matrices, - buffers.getBuffer(RenderType.entitySolid(texture)), packedLight, OverlayTexture.NO_OVERLAY); + final BufferedQuads worldRenderer = new BufferedQuads(pose, vertices, packedLight, OverlayTexture.NO_OVERLAY); // render shaft worldRenderer.pos(+radius, bottomHeight, -radius).tex(shaftMinU,shaftMinV).endVertex(); @@ -107,15 +125,9 @@ public void render(final HydroturbineEntity entity, final float entityYaw, final // render spinning (or not) blades float spin1, spin2, spin3; - if(e.isSpinning){ - spin1 = e.rotation + HydroturbineEntity.DEGREES_PER_TICK * partialTick; - spin2 = spin1 + 120; - spin3 = spin1 - 120; - } else { - spin1 = e.rotation; - spin2 = spin1 + 120; - spin3 = spin1 - 120; - } + spin1 = rotation; + spin2 = spin1 + 120; + spin3 = spin1 - 120; final float bladeWidth = 3*pixel; final float bladeLength = 6*pixel; final float bladeOffset = 1*pixel; @@ -173,14 +185,8 @@ public void render(final HydroturbineEntity entity, final float entityYaw, final worldRenderer.pos(cos3b*bladeOffset, sin3b*bladeOffset, depthDelta-axelLength).tex(bladeMinU,bladeMinV).endVertex(); // inner, leading - matrices.popPose(); - super.render(e, entityYaw, partialTick, matrices, buffers, packedLight); } } - @Override - public ResourceLocation getTextureLocation(final HydroturbineEntity e) { - return texture; - } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/graphics/LaserDrillRenderer.java b/src/main/java/zone/moddev/mc/baseelectric/graphics/LaserDrillRenderer.java index 84450ce1..e0e6973d 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/graphics/LaserDrillRenderer.java +++ b/src/main/java/zone/moddev/mc/baseelectric/graphics/LaserDrillRenderer.java @@ -4,20 +4,22 @@ import zone.moddev.mc.baseelectric.machines.ElectricDrillTileEntity; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.rendertype.RenderType; +import net.minecraft.client.renderer.SubmitNodeCollector; +import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState; +import net.minecraft.client.renderer.feature.ModelFeatureRenderer; +import net.minecraft.client.renderer.state.CameraRenderState; +import net.minecraft.world.phys.Vec3; +import net.minecraft.client.renderer.texture.OverlayTexture; import com.mojang.math.Axis; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -@OnlyIn(Dist.CLIENT) // This is needed for classes that extend client-only classes -public class LaserDrillRenderer implements BlockEntityRenderer{ +import net.minecraft.resources.Identifier; +public class LaserDrillRenderer implements BlockEntityRenderer{ - private final ResourceLocation texture = ResourceLocation.parse(ElectricAdvantage.MODID+":textures/materials/laser_beam.png"); + private final Identifier texture = Identifier.parse(ElectricAdvantage.MODID+":textures/materials/laser_beam.png"); private final RenderType beamType = ElectricRenderTypes.unshaded(texture, false); @@ -25,23 +27,42 @@ public LaserDrillRenderer(BlockEntityRendererProvider.Context context) { } - @Override + public static final class State extends BlockEntityRenderState { + float length; + Direction facing = Direction.DOWN; + } + + @Override public State createRenderState() { return new State(); } + + @Override public void extractRenderState(ElectricDrillTileEntity entity, State state, float partialTick, + Vec3 camera, ModelFeatureRenderer.CrumblingOverlay breaking) { + BlockEntityRenderer.super.extractRenderState(entity, state, partialTick, camera, breaking); + state.length = entity.getDrillLength(); + state.facing = entity.getFacing(); + } + + @Override public void submit(State state, PoseStack matrices, SubmitNodeCollector collector, CameraRenderState camera) { + if (state.length <= 0) return; + transform(matrices, state.facing); + float length = state.length; + collector.submitCustomGeometry(matrices, beamType, + (pose, vertices) -> draw(length, pose, vertices, OverlayTexture.NO_OVERLAY)); + matrices.popPose(); + } + public void render(final ElectricDrillTileEntity e, final float partialTick, final PoseStack matrices, final MultiBufferSource buffers, final int packedLight, final int packedOverlay) { float laserBlastLength = e.getDrillLength(); if(laserBlastLength > 0){ - final float laserU0 = 0; - final float laserU1 = 0; - final float laserV0 = 1.0f; - final float laserV1 = 1.0f; - - final float laserRadius = 0.125f; - - - Direction dir = e.getFacing(); + transform(matrices, e.getFacing()); + draw(laserBlastLength, matrices.last(), buffers.getBuffer(beamType), packedOverlay); + matrices.popPose(); + } + } + private static void transform(PoseStack matrices, Direction dir) { float rotY = 0, rotX = 0; switch(dir){ case NORTH:{ @@ -78,8 +99,13 @@ public void render(final ElectricDrillTileEntity e, final float partialTick, fin matrices.translate(0.5f, 0.5f, 0.5f); matrices.mulPose(Axis.YP.rotationDegrees(rotY)); matrices.mulPose(Axis.XP.rotationDegrees(rotX)); - final BufferedQuads worldRenderer = new BufferedQuads(matrices, - buffers.getBuffer(beamType), 15 << 20 | 15 << 4, packedOverlay); + } + + private static void draw(float laserBlastLength, PoseStack.Pose pose, + com.mojang.blaze3d.vertex.VertexConsumer vertices, int packedOverlay) { + final float laserU0 = 0, laserU1 = 0, laserV0 = 1, laserV1 = 1; + final float laserRadius = 0.125f; + final BufferedQuads worldRenderer = new BufferedQuads(pose, vertices, 15 << 20 | 15 << 4, packedOverlay); final double x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4; x1 = 0; @@ -117,9 +143,6 @@ public void render(final ElectricDrillTileEntity e, final float partialTick, fin worldRenderer.pos( x3, y4, z4).tex(laserU1, laserV0).endVertex(); worldRenderer.pos( x3, y3, z3).tex(laserU0, laserV0).endVertex(); - matrices.popPose(); - - } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/graphics/LaserTurretRenderer.java b/src/main/java/zone/moddev/mc/baseelectric/graphics/LaserTurretRenderer.java index b81ceda3..237682c9 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/graphics/LaserTurretRenderer.java +++ b/src/main/java/zone/moddev/mc/baseelectric/graphics/LaserTurretRenderer.java @@ -4,28 +4,81 @@ import zone.moddev.mc.baseelectric.machines.LaserTurretTileEntity; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.rendertype.RenderType; +import net.minecraft.client.renderer.SubmitNodeCollector; +import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState; +import net.minecraft.client.renderer.feature.ModelFeatureRenderer; +import net.minecraft.client.renderer.state.CameraRenderState; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.world.phys.Vec3; import com.mojang.math.Axis; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -@OnlyIn(Dist.CLIENT) // This is needed for classes that extend client-only classes -public class LaserTurretRenderer implements BlockEntityRenderer{ +import net.minecraft.resources.Identifier; +public class LaserTurretRenderer implements BlockEntityRenderer{ - private final ResourceLocation texture = ResourceLocation.parse(ElectricAdvantage.MODID+":textures/entity/laser_turret.png"); + private final Identifier texture = Identifier.parse(ElectricAdvantage.MODID+":textures/entity/laser_turret.png"); private final RenderType renderType = ElectricRenderTypes.unshaded(texture, true); public LaserTurretRenderer(BlockEntityRendererProvider.Context context) { } - @Override + public static final class State extends BlockEntityRenderState { + boolean active; + boolean showBeam; + double length; + float yaw; + float pitch; + } + + @Override public State createRenderState() { return new State(); } + + private static void capture(LaserTurretTileEntity entity, State state, float partialTick) { + state.active = entity.isActive(); + state.showBeam = entity.showLaserLine(); + state.length = entity.laserBlastLength; + state.yaw = -((1 - partialTick) * entity.rotOldYaw + partialTick * entity.rotYaw) - 90; + state.pitch = (1 - partialTick) * entity.rotOldPitch + partialTick * entity.rotPitch; + } + + @Override public void extractRenderState(LaserTurretTileEntity entity, State state, float partialTick, + Vec3 camera, ModelFeatureRenderer.CrumblingOverlay breaking) { + BlockEntityRenderer.super.extractRenderState(entity, state, partialTick, camera, breaking); + capture(entity, state, partialTick); + } + + @Override public void submit(State state, PoseStack matrices, SubmitNodeCollector collector, CameraRenderState camera) { + State snapshot = new State(); + snapshot.active = state.active; + snapshot.showBeam = state.showBeam; + snapshot.length = state.length; + transform(matrices, state.yaw, state.pitch); + int light = state.lightCoords; + collector.submitCustomGeometry(matrices, renderType, + (pose, vertices) -> draw(snapshot, pose, vertices, light, OverlayTexture.NO_OVERLAY)); + matrices.popPose(); + } + public void render(final LaserTurretTileEntity e, final float partialTick, final PoseStack matrices, final MultiBufferSource buffers, final int packedLight, final int packedOverlay) { + State state = new State(); + capture(e, state, partialTick); + transform(matrices, state.yaw, state.pitch); + draw(state, matrices.last(), buffers.getBuffer(renderType), packedLight, packedOverlay); + matrices.popPose(); + } + + private static void transform(PoseStack matrices, float yaw, float pitch) { + matrices.pushPose(); + matrices.translate(0.5f, 0.75f, 0.5f); + matrices.mulPose(Axis.YP.rotationDegrees(yaw)); + matrices.mulPose(Axis.XP.rotationDegrees(pitch)); + } + + private static void draw(State state, PoseStack.Pose pose, + com.mojang.blaze3d.vertex.VertexConsumer vertices, int packedLight, int packedOverlay) { final float sideU0 = 0; final float sideU1 = 0.5f; final float sideV0 = 0; @@ -34,7 +87,7 @@ public void render(final LaserTurretTileEntity e, final float partialTick, final final float endU1 = 1; final float endV0; final float endV1; - if(e.isActive()){ + if(state.active){ endV0 = 0; endV1 = 0.5f; }else{ @@ -51,17 +104,7 @@ public void render(final LaserTurretTileEntity e, final float partialTick, final final float laserRadius = 0.125f; - float tickRemainder = 1 - partialTick; - float yaw = -1*(tickRemainder * e.rotOldYaw + partialTick * e.rotYaw) - 90; - float pitch = tickRemainder * e.rotOldPitch + partialTick * e.rotPitch; - - - matrices.pushPose(); - matrices.translate(0.5f, 0.75f, 0.5f); - matrices.mulPose(Axis.YP.rotationDegrees(yaw)); - matrices.mulPose(Axis.XP.rotationDegrees(pitch)); - BufferedQuads worldRenderer = new BufferedQuads(matrices, - buffers.getBuffer(renderType), packedLight, packedOverlay); + BufferedQuads worldRenderer = new BufferedQuads(pose, vertices, packedLight, packedOverlay); worldRenderer.pos( radius, radius, -radius).tex(endU0, endV0).endVertex(); worldRenderer.pos( radius,-radius, -radius).tex(endU0, endV1).endVertex(); @@ -93,14 +136,14 @@ public void render(final LaserTurretTileEntity e, final float partialTick, final worldRenderer.pos( radius,-radius, -radius).tex(sideU1, sideV1).endVertex(); worldRenderer.pos( radius,-radius, radius).tex(sideU1, sideV0).endVertex(); - if(e.showLaserLine() && e.laserBlastLength > 0){ + if(state.showBeam && state.length > 0){ final double x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4; x1 = 0; y1 = -laserRadius; z1 = 0; x2 = 0; y2 = laserRadius; - z2 = -e.laserBlastLength; + z2 = -state.length; x3 = -laserRadius; y3 = 0; @@ -109,8 +152,7 @@ public void render(final LaserTurretTileEntity e, final float partialTick, final y4 = 0; z4 = z2; - worldRenderer = new BufferedQuads(matrices, - buffers.getBuffer(renderType), 15 << 20 | 15 << 4, packedOverlay); + worldRenderer = new BufferedQuads(pose, vertices, 15 << 20 | 15 << 4, packedOverlay); worldRenderer.pos( x1, y1, z1).tex(laserU0, laserV1).endVertex(); worldRenderer.pos( x2, y1, z2).tex(laserU1, laserV1).endVertex(); @@ -135,7 +177,6 @@ public void render(final LaserTurretTileEntity e, final float partialTick, final } - matrices.popPose(); } diff --git a/src/main/java/zone/moddev/mc/baseelectric/gui/ArcFurnaceGUI.java b/src/main/java/zone/moddev/mc/baseelectric/gui/ArcFurnaceGUI.java index d32d633f..3073bb12 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/gui/ArcFurnaceGUI.java +++ b/src/main/java/zone/moddev/mc/baseelectric/gui/ArcFurnaceGUI.java @@ -1,7 +1,5 @@ package zone.moddev.mc.baseelectric.gui; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.machines.ElectricMachineTileEntity; @@ -10,19 +8,19 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; public class ArcFurnaceGUI extends SimpleMachineGUI{ public ArcFurnaceGUI() { - super(ResourceLocation.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_furnace_gui.png"), + super(Identifier.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_furnace_gui.png"), Integer2D.fromCoordinates(12,34, 12,55, 12,76, 12,97, 124,45, 145,45, 124,66, 145,66, 124,87, 145,87)); for(int i = 4; i < 10; i++)super.specialSlots.put(i, (SlotContext c)->new Slot(c.machineInventory,c.slotIndex,c.screenPositionX,c.screenPositionY){ @Override public void onTake(Player player, ItemStack stack) { - stack.onCraftedBy(player.getCommandSenderWorld(), player, stack.getCount()); + stack.onCraftedBy(player, stack.getCount()); super.onTake(player, stack); } @Override @@ -50,7 +48,6 @@ public void onTake(Player player, ItemStack stack) * @param z This is the z coordinate (no units) into the depth of the screen */ @Override - @OnlyIn(Dist.CLIENT) public void drawGUIDecorations(Object srcEntity, GUIContainer guiContainer, int x, int y, float z){ if(srcEntity instanceof ElectricMachineTileEntity){ ElectricMachineTileEntity te = (ElectricMachineTileEntity)srcEntity; diff --git a/src/main/java/zone/moddev/mc/baseelectric/gui/BatteryArrayGUI.java b/src/main/java/zone/moddev/mc/baseelectric/gui/BatteryArrayGUI.java index 3d72a715..1de09440 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/gui/BatteryArrayGUI.java +++ b/src/main/java/zone/moddev/mc/baseelectric/gui/BatteryArrayGUI.java @@ -1,18 +1,16 @@ package zone.moddev.mc.baseelectric.gui; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.machines.ElectricBatteryArrayTileEntity; import cyano.poweradvantage.api.simple.SimpleMachineGUI; import zone.moddev.mc.basepower.math.Integer2D; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; public class BatteryArrayGUI extends SimpleMachineGUI{ public BatteryArrayGUI() { - super(ResourceLocation.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_battery_array_gui.png"), + super(Identifier.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_battery_array_gui.png"), Integer2D.fromCoordinates( 27, 32, 27, 53, @@ -46,7 +44,6 @@ public BatteryArrayGUI() { * @param z This is the z coordinate (no units) into the depth of the screen */ @Override - @OnlyIn(Dist.CLIENT) public void drawGUIDecorations(Object srcEntity, GUIContainer guiContainer, int x, int y, float z){ if(srcEntity instanceof ElectricBatteryArrayTileEntity){ ElectricBatteryArrayTileEntity te = (ElectricBatteryArrayTileEntity)srcEntity; diff --git a/src/main/java/zone/moddev/mc/baseelectric/gui/ElectricDrillGUI.java b/src/main/java/zone/moddev/mc/baseelectric/gui/ElectricDrillGUI.java index 1743f6da..7591c33a 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/gui/ElectricDrillGUI.java +++ b/src/main/java/zone/moddev/mc/baseelectric/gui/ElectricDrillGUI.java @@ -1,18 +1,16 @@ package zone.moddev.mc.baseelectric.gui; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.machines.ElectricMachineTileEntity; import cyano.poweradvantage.api.simple.SimpleMachineGUI; import zone.moddev.mc.basepower.math.Integer2D; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; public class ElectricDrillGUI extends SimpleMachineGUI{ public ElectricDrillGUI() { - super(ResourceLocation.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_drill_gui.png"), + super(Identifier.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_drill_gui.png"), Integer2D.fromCoordinates( 124,45, 145,45, 124,66, 145,66, 124,87, 145,87)); } @@ -37,7 +35,6 @@ public ElectricDrillGUI() { * @param z This is the z coordinate (no units) into the depth of the screen */ @Override - @OnlyIn(Dist.CLIENT) public void drawGUIDecorations(Object srcEntity, GUIContainer guiContainer, int x, int y, float z){ if(srcEntity instanceof ElectricMachineTileEntity){ ElectricMachineTileEntity te = (ElectricMachineTileEntity)srcEntity; diff --git a/src/main/java/zone/moddev/mc/baseelectric/gui/ElectricPumpGUI.java b/src/main/java/zone/moddev/mc/baseelectric/gui/ElectricPumpGUI.java index ae467abc..fb3a9b34 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/gui/ElectricPumpGUI.java +++ b/src/main/java/zone/moddev/mc/baseelectric/gui/ElectricPumpGUI.java @@ -1,19 +1,17 @@ package zone.moddev.mc.baseelectric.gui; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.machines.ElectricPumpTileEntity; import cyano.poweradvantage.api.simple.SimpleMachineGUI; import zone.moddev.mc.basepower.math.Integer2D; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import cyano.poweradvantage.api.fluid.FluidStack; public class ElectricPumpGUI extends SimpleMachineGUI{ public ElectricPumpGUI() { - super(ResourceLocation.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_pump_gui.png"), + super(Identifier.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_pump_gui.png"), new Integer2D[0]); } @@ -37,7 +35,6 @@ public ElectricPumpGUI() { * @param z This is the z coordinate (no units) into the depth of the screen */ @Override - @OnlyIn(Dist.CLIENT) public void drawGUIDecorations(Object srcEntity, GUIContainer guiContainer, int x, int y, float z){ if(srcEntity instanceof ElectricPumpTileEntity){ ElectricPumpTileEntity te = (ElectricPumpTileEntity)srcEntity; diff --git a/src/main/java/zone/moddev/mc/baseelectric/gui/ElectricStillGUI.java b/src/main/java/zone/moddev/mc/baseelectric/gui/ElectricStillGUI.java index 064b2a39..ffdbee85 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/gui/ElectricStillGUI.java +++ b/src/main/java/zone/moddev/mc/baseelectric/gui/ElectricStillGUI.java @@ -1,19 +1,17 @@ package zone.moddev.mc.baseelectric.gui; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.machines.ElectricStillTileEntity; import cyano.poweradvantage.api.simple.SimpleMachineGUI; import zone.moddev.mc.basepower.math.Integer2D; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import cyano.poweradvantage.api.fluid.FluidStack; public class ElectricStillGUI extends SimpleMachineGUI{ public ElectricStillGUI() { - super(ResourceLocation.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_still_gui.png"), + super(Identifier.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_still_gui.png"), new Integer2D[0]); } @@ -37,7 +35,6 @@ public ElectricStillGUI() { * @param z This is the z coordinate (no units) into the depth of the screen */ @Override - @OnlyIn(Dist.CLIENT) public void drawGUIDecorations(Object srcEntity, GUIContainer guiContainer, int x, int y, float z){ if(srcEntity instanceof ElectricStillTileEntity){ ElectricStillTileEntity te = (ElectricStillTileEntity)srcEntity; diff --git a/src/main/java/zone/moddev/mc/baseelectric/gui/FabricatorGUI.java b/src/main/java/zone/moddev/mc/baseelectric/gui/FabricatorGUI.java index 9a0c1d2d..4a385aa9 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/gui/FabricatorGUI.java +++ b/src/main/java/zone/moddev/mc/baseelectric/gui/FabricatorGUI.java @@ -1,7 +1,5 @@ package zone.moddev.mc.baseelectric.gui; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.machines.ElectricMachineTileEntity; @@ -10,12 +8,12 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; public class FabricatorGUI extends SimpleMachineGUI{ public FabricatorGUI() { - super(ResourceLocation.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_fabricator_gui.png"), + super(Identifier.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_fabricator_gui.png"), Integer2D.fromCoordinates( 12,34, 33,34, 54,34, 12,55, 33,55, 54,55, @@ -31,7 +29,7 @@ public FabricatorGUI() { @Override public void onTake(Player player, ItemStack stack) { - stack.onCraftedBy(player.getCommandSenderWorld(), player, stack.getCount()); + stack.onCraftedBy(player, stack.getCount()); super.onTake(player, stack); } @Override @@ -59,7 +57,6 @@ public void onTake(Player player, ItemStack stack) * @param z This is the z coordinate (no units) into the depth of the screen */ @Override - @OnlyIn(Dist.CLIENT) public void drawGUIDecorations(Object srcEntity, GUIContainer guiContainer, int x, int y, float z){ if(srcEntity instanceof ElectricMachineTileEntity){ ElectricMachineTileEntity te = (ElectricMachineTileEntity)srcEntity; diff --git a/src/main/java/zone/moddev/mc/baseelectric/gui/GUIHelper.java b/src/main/java/zone/moddev/mc/baseelectric/gui/GUIHelper.java index 27f9cb36..329c8a55 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/gui/GUIHelper.java +++ b/src/main/java/zone/moddev/mc/baseelectric/gui/GUIHelper.java @@ -1,12 +1,10 @@ package zone.moddev.mc.baseelectric.gui; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import cyano.poweradvantage.api.simple.SimpleMachineGUI.GUIContainer; import zone.moddev.mc.basepower.gui.FluidTankGUI; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import cyano.poweradvantage.api.fluid.FluidStack; import java.util.HashMap; @@ -25,16 +23,14 @@ public class GUIHelper { private static final int LED_BAR_W8 = 4; - private static final Map realTextureLocationCache = new HashMap<>(); + private static final Map realTextureLocationCache = new HashMap<>(); - @OnlyIn(Dist.CLIENT) public static void drawIndicatorLight(boolean on,GUIContainer gc, int xOffset, int yOffset){ if(on){ gc.blit(8+xOffset, 8+yOffset, INDICATOR_LED_X, INDICATOR_LED_Y, INDICATOR_LED_W, INDICATOR_LED_H); } } - @OnlyIn(Dist.CLIENT) public static void drawProgressBar(int x, int y, float progress, GUIContainer gc){ int w = progressBarWidth(progress); if(w == 0) return; @@ -48,10 +44,9 @@ static int progressBarWidth(float progress) { } - @OnlyIn(Dist.CLIENT) public static void drawFluidBar(FluidStack fs, float barHeight, int xPos, int yPos, GUIContainer guiContainer, int x, int y, float z, - ResourceLocation displayImage){ + Identifier displayImage){ barHeight = Float.isFinite(barHeight) ? Math.max(0F, Math.min(1F, barHeight)) : 0F; final int w = 16; diff --git a/src/main/java/zone/moddev/mc/baseelectric/gui/GenericMachineGUI.java b/src/main/java/zone/moddev/mc/baseelectric/gui/GenericMachineGUI.java index 6829b2b1..4f831b44 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/gui/GenericMachineGUI.java +++ b/src/main/java/zone/moddev/mc/baseelectric/gui/GenericMachineGUI.java @@ -1,18 +1,16 @@ package zone.moddev.mc.baseelectric.gui; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.machines.ElectricMachineTileEntity; import cyano.poweradvantage.api.simple.SimpleMachineGUI; import zone.moddev.mc.basepower.math.Integer2D; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; public class GenericMachineGUI extends SimpleMachineGUI{ public GenericMachineGUI() { - super(ResourceLocation.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_machine_gui.png"), new Integer2D[0]); + super(Identifier.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_machine_gui.png"), new Integer2D[0]); } /** @@ -35,7 +33,6 @@ public GenericMachineGUI() { * @param z This is the z coordinate (no units) into the depth of the screen */ @Override - @OnlyIn(Dist.CLIENT) public void drawGUIDecorations(Object srcEntity, GUIContainer guiContainer, int x, int y, float z){ if(srcEntity instanceof ElectricMachineTileEntity){ ElectricMachineTileEntity te = (ElectricMachineTileEntity)srcEntity; diff --git a/src/main/java/zone/moddev/mc/baseelectric/gui/GrowthChamberControllerGUI.java b/src/main/java/zone/moddev/mc/baseelectric/gui/GrowthChamberControllerGUI.java index 5813eaff..a3865c72 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/gui/GrowthChamberControllerGUI.java +++ b/src/main/java/zone/moddev/mc/baseelectric/gui/GrowthChamberControllerGUI.java @@ -1,18 +1,16 @@ package zone.moddev.mc.baseelectric.gui; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.machines.GrowthChamberControllerTileEntity; import cyano.poweradvantage.api.simple.SimpleMachineGUI; import zone.moddev.mc.basepower.math.Integer2D; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; public class GrowthChamberControllerGUI extends SimpleMachineGUI{ public GrowthChamberControllerGUI() { - super(ResourceLocation.parse(ElectricAdvantage.MODID+":textures/gui/container/growth_chamber_controller_gui.png"), + super(Identifier.parse(ElectricAdvantage.MODID+":textures/gui/container/growth_chamber_controller_gui.png"), Integer2D.fromCoordinates(100,74)); } @@ -36,7 +34,6 @@ public GrowthChamberControllerGUI() { * @param z This is the z coordinate (no units) into the depth of the screen */ @Override - @OnlyIn(Dist.CLIENT) public void drawGUIDecorations(Object srcEntity, GUIContainer guiContainer, int x, int y, float z){ if(srcEntity instanceof GrowthChamberControllerTileEntity){ GrowthChamberControllerTileEntity te = (GrowthChamberControllerTileEntity)srcEntity; diff --git a/src/main/java/zone/moddev/mc/baseelectric/gui/GrowthChamberGUI.java b/src/main/java/zone/moddev/mc/baseelectric/gui/GrowthChamberGUI.java index 0444f265..23c3206f 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/gui/GrowthChamberGUI.java +++ b/src/main/java/zone/moddev/mc/baseelectric/gui/GrowthChamberGUI.java @@ -1,18 +1,16 @@ package zone.moddev.mc.baseelectric.gui; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.machines.ElectricMachineTileEntity; import cyano.poweradvantage.api.simple.SimpleMachineGUI; import zone.moddev.mc.basepower.math.Integer2D; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; public class GrowthChamberGUI extends SimpleMachineGUI{ public GrowthChamberGUI() { - super(ResourceLocation.parse(ElectricAdvantage.MODID+":textures/gui/container/growth_chamber_gui.png"), + super(Identifier.parse(ElectricAdvantage.MODID+":textures/gui/container/growth_chamber_gui.png"), Integer2D.fromCoordinates(12,38, 12,59, 12,80, 124,55, 145,55, 124,76, 145,76, 124,97, 145,97)); } @@ -37,7 +35,6 @@ public GrowthChamberGUI() { * @param z This is the z coordinate (no units) into the depth of the screen */ @Override - @OnlyIn(Dist.CLIENT) public void drawGUIDecorations(Object srcEntity, GUIContainer guiContainer, int x, int y, float z){ if(srcEntity instanceof ElectricMachineTileEntity){ ElectricMachineTileEntity te = (ElectricMachineTileEntity)srcEntity; diff --git a/src/main/java/zone/moddev/mc/baseelectric/gui/OvenGUI.java b/src/main/java/zone/moddev/mc/baseelectric/gui/OvenGUI.java index 72819ff8..37daa070 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/gui/OvenGUI.java +++ b/src/main/java/zone/moddev/mc/baseelectric/gui/OvenGUI.java @@ -1,7 +1,5 @@ package zone.moddev.mc.baseelectric.gui; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.machines.ElectricMachineTileEntity; @@ -10,18 +8,18 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; public class OvenGUI extends SimpleMachineGUI{ public OvenGUI() { - super(ResourceLocation.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_oven_gui.png"), + super(Identifier.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_oven_gui.png"), Integer2D.fromCoordinates(27,67, 133,67)); super.specialSlots.put(1, (SlotContext c)->new Slot(c.machineInventory,c.slotIndex,c.screenPositionX,c.screenPositionY){ @Override public void onTake(Player player, ItemStack stack) { - stack.onCraftedBy(player.getCommandSenderWorld(), player, stack.getCount()); + stack.onCraftedBy(player, stack.getCount()); super.onTake(player, stack); } @Override @@ -49,7 +47,6 @@ public void onTake(Player player, ItemStack stack) * @param z This is the z coordinate (no units) into the depth of the screen */ @Override - @OnlyIn(Dist.CLIENT) public void drawGUIDecorations(Object srcEntity, GUIContainer guiContainer, int x, int y, float z){ if(srcEntity instanceof ElectricMachineTileEntity){ ElectricMachineTileEntity te = (ElectricMachineTileEntity)srcEntity; diff --git a/src/main/java/zone/moddev/mc/baseelectric/gui/PlasticRefineryGUI.java b/src/main/java/zone/moddev/mc/baseelectric/gui/PlasticRefineryGUI.java index 16285870..5f95d47e 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/gui/PlasticRefineryGUI.java +++ b/src/main/java/zone/moddev/mc/baseelectric/gui/PlasticRefineryGUI.java @@ -1,19 +1,17 @@ package zone.moddev.mc.baseelectric.gui; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.machines.PlasticRefineryTileEntity; import cyano.poweradvantage.api.simple.SimpleMachineGUI; import zone.moddev.mc.basepower.math.Integer2D; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import cyano.poweradvantage.api.fluid.FluidStack; public class PlasticRefineryGUI extends SimpleMachineGUI{ public PlasticRefineryGUI() { - super(ResourceLocation.parse(ElectricAdvantage.MODID+":textures/gui/container/plastic_refinery_gui.png"), + super(Identifier.parse(ElectricAdvantage.MODID+":textures/gui/container/plastic_refinery_gui.png"), Integer2D.fromCoordinates(133,67)); } @@ -37,7 +35,6 @@ public PlasticRefineryGUI() { * @param z This is the z coordinate (no units) into the depth of the screen */ @Override - @OnlyIn(Dist.CLIENT) public void drawGUIDecorations(Object srcEntity, GUIContainer guiContainer, int x, int y, float z){ if(srcEntity instanceof PlasticRefineryTileEntity){ PlasticRefineryTileEntity te = (PlasticRefineryTileEntity)srcEntity; diff --git a/src/main/java/zone/moddev/mc/baseelectric/gui/PowerGeneratorGUI.java b/src/main/java/zone/moddev/mc/baseelectric/gui/PowerGeneratorGUI.java index 41f952d2..2659a677 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/gui/PowerGeneratorGUI.java +++ b/src/main/java/zone/moddev/mc/baseelectric/gui/PowerGeneratorGUI.java @@ -1,18 +1,16 @@ package zone.moddev.mc.baseelectric.gui; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.machines.ElectricGeneratorTileEntity; import cyano.poweradvantage.api.simple.SimpleMachineGUI; import zone.moddev.mc.basepower.math.Integer2D; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; public class PowerGeneratorGUI extends SimpleMachineGUI{ public PowerGeneratorGUI() { - super(ResourceLocation.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_generator_gui.png"), new Integer2D[0]); + super(Identifier.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_generator_gui.png"), new Integer2D[0]); } /** @@ -35,7 +33,6 @@ public PowerGeneratorGUI() { * @param z This is the z coordinate (no units) into the depth of the screen */ @Override - @OnlyIn(Dist.CLIENT) public void drawGUIDecorations(Object srcEntity, GUIContainer guiContainer, int x, int y, float z){ if(srcEntity instanceof ElectricGeneratorTileEntity){ ElectricGeneratorTileEntity te = (ElectricGeneratorTileEntity)srcEntity; diff --git a/src/main/java/zone/moddev/mc/baseelectric/gui/RockCrusherGUI.java b/src/main/java/zone/moddev/mc/baseelectric/gui/RockCrusherGUI.java index 42acc711..8bb078cd 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/gui/RockCrusherGUI.java +++ b/src/main/java/zone/moddev/mc/baseelectric/gui/RockCrusherGUI.java @@ -1,18 +1,16 @@ package zone.moddev.mc.baseelectric.gui; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.machines.ElectricMachineTileEntity; import cyano.poweradvantage.api.simple.SimpleMachineGUI; import zone.moddev.mc.basepower.math.Integer2D; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; public class RockCrusherGUI extends SimpleMachineGUI{ public RockCrusherGUI() { - super(ResourceLocation.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_crusher_gui.png"), + super(Identifier.parse(ElectricAdvantage.MODID+":textures/gui/container/electric_crusher_gui.png"), Integer2D.fromCoordinates(12,45, 12,66, 12,87, 124,45, 145,45, 124,66, 145,66, 124,87, 145,87)); } @@ -37,7 +35,6 @@ public RockCrusherGUI() { * @param z This is the z coordinate (no units) into the depth of the screen */ @Override - @OnlyIn(Dist.CLIENT) public void drawGUIDecorations(Object srcEntity, GUIContainer guiContainer, int x, int y, float z){ if(srcEntity instanceof ElectricMachineTileEntity){ ElectricMachineTileEntity te = (ElectricMachineTileEntity)srcEntity; diff --git a/src/main/java/zone/moddev/mc/baseelectric/init/Blocks.java b/src/main/java/zone/moddev/mc/baseelectric/init/Blocks.java index 722c543a..a9bd73a6 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/init/Blocks.java +++ b/src/main/java/zone/moddev/mc/baseelectric/init/Blocks.java @@ -4,12 +4,12 @@ import java.util.Map; import cyano.poweradvantage.api.GUIBlock; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.world.level.block.Block; import net.minecraft.world.item.Item; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.eventbus.api.listener.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegisterEvent; @@ -92,7 +92,11 @@ private static synchronized void constructBlocks() { growth_chamber = (GUIBlock) add(new GrowthChamberBlock(), "growth_chamber"); growth_chamber_controller = (GUIBlock) add(new GrowthChamberControllerBlock(), "growth_chamber_controller"); oven = (GUIBlock) add(new ElectricOvenBlock(), "electric_oven"); - electric_switch = add(new BlockPowerSwitch(Power.ELECTRIC_POWER), "electric_switch"); + electric_switch = add(new BlockPowerSwitch(Power.ELECTRIC_POWER, + Block.Properties.of().setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("electric_switch")) + .mapColor(net.minecraft.world.level.material.MapColor.STONE) + .pushReaction(net.minecraft.world.level.material.PushReaction.BLOCK) + .forceSolidOn().strength(0.75F)), "electric_switch"); electric_pump = (GUIBlock) add(new ElectricPumpBlock(), "electric_pump"); electric_still = (GUIBlock) add(new ElectricStillBlock(), "electric_still"); plastic_refinery = (GUIBlock) add(new PlasticRefineryBlock(), "plastic_refinery"); @@ -108,17 +112,18 @@ private static Block add(Block block, String id) { @SubscribeEvent public static void registerBlocks(RegisterEvent event) { event.register(ForgeRegistries.Keys.BLOCKS, registry -> { constructBlocks(); - ALL_BLOCKS.forEach((id, block) -> registry.register(ResourceLocation.fromNamespaceAndPath(ElectricAdvantage.MODID, id), block)); + ALL_BLOCKS.forEach((id, block) -> registry.register(Identifier.fromNamespaceAndPath(ElectricAdvantage.MODID, id), block)); }); } @SubscribeEvent public static void registerBlockItems(RegisterEvent event) { event.register(ForgeRegistries.Keys.ITEMS, registry -> ALL_BLOCKS.forEach((id, block) -> { - BlockItem item = new BlockItem(block, new Item.Properties()); + BlockItem item = new BlockItem(block, new Item.Properties() + .setId(zone.moddev.mc.baseelectric.util.RegistryIds.item(id)).useBlockDescriptionPrefix()); if (!"pump_pipe_electric".equals(id) && !"laser_turret_evil".equals(id)) { ItemGroups.show(item); } - registry.register(ResourceLocation.fromNamespaceAndPath(ElectricAdvantage.MODID, id), item); + registry.register(Identifier.fromNamespaceAndPath(ElectricAdvantage.MODID, id), item); })); } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/init/Entities.java b/src/main/java/zone/moddev/mc/baseelectric/init/Entities.java index f4dfbdc9..a64bde2e 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/init/Entities.java +++ b/src/main/java/zone/moddev/mc/baseelectric/init/Entities.java @@ -1,12 +1,12 @@ package zone.moddev.mc.baseelectric.init; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.MobCategory; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.eventbus.api.listener.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegisterEvent; @@ -78,11 +78,11 @@ private static void registerTiles(RegisterEvent.RegisterHelper { - ResourceLocation id = ResourceLocation.fromNamespaceAndPath(ElectricAdvantage.MODID, "hydroturbine"); + Identifier id = Identifier.fromNamespaceAndPath(ElectricAdvantage.MODID, "hydroturbine"); HYDROTURBINE = EntityType.Builder.of(HydroturbineEntity::new, MobCategory.MISC) .sized(0.9375F, 0.9375F) .setTrackingRange(64).setUpdateInterval(1).setShouldReceiveVelocityUpdates(true) - .build(id.toString()); + .build(net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.ENTITY_TYPE, id)); registry.register(id, HYDROTURBINE); }); } @@ -90,8 +90,8 @@ private static void registerTiles(RegisterEvent.RegisterHelper BlockEntityType tile( RegisterEvent.RegisterHelper> event, String id, BlockEntityType.BlockEntitySupplier factory, net.minecraft.world.level.block.Block... blocks) { - BlockEntityType type = BlockEntityType.Builder.of(factory, blocks).build(null); - event.register(ResourceLocation.fromNamespaceAndPath(ElectricAdvantage.MODID, id), type); + BlockEntityType type = new BlockEntityType<>(factory, java.util.Set.of(blocks)); + event.register(Identifier.fromNamespaceAndPath(ElectricAdvantage.MODID, id), type); return type; } diff --git a/src/main/java/zone/moddev/mc/baseelectric/init/Items.java b/src/main/java/zone/moddev/mc/baseelectric/init/Items.java index 97bd4f1c..3a7434bf 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/init/Items.java +++ b/src/main/java/zone/moddev/mc/baseelectric/init/Items.java @@ -4,9 +4,9 @@ import java.util.Map; import java.util.Set; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.world.item.Item; -import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.eventbus.api.listener.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegisterEvent; @@ -44,27 +44,27 @@ public static void init() {} private static synchronized void constructItems() { if (initialized) return; - blank_circuit_board = add("blank_circuit_board", new Item(properties())); - control_circuit = add("control_circuit", new Item(properties())); - integrated_circuit = add("integrated_circuit", new Item(properties())); - power_supply_unit = add("psu", new Item(properties())); - silicon_ingot = add("silicon_ingot", new Item(properties())); - silicon_blend = add("silicon_mix", new Item(properties())); - solder_blend = add("solder_mix", new Item(properties())); - solder = add("solder", new Item(properties())); - lithium_ingot = add("li_ingot", new Item(properties())); - lithium_powder = add("li_powder", new Item(properties())); - lithium_nugget = add("li_nugget", new Item(properties())); - sulfur_powder = add("sulfur_powder", new Item(properties())); - petrolplastic_ingot = add("petrolplastic_ingot", new Item(properties())); - lead_acid_battery = add("lead_acid_battery", new BatteryItem(Power.LEAD_ACID_BATTERY_CAPACITY, properties())); - nickel_hydride_battery = add("nickel_hydride_battery", new BatteryItem(Power.NICKEL_HYDRIDE_BATTERY_CAPACITY, properties())); - alkaline_battery = add("alkaline_battery", new BatteryItem(Power.ALKALINE_BATTERY_CAPACITY, properties())); - lithium_battery = add("lithium_battery", new BatteryItem(Power.LITHIUM_BATTERY_CAPACITY, properties())); + blank_circuit_board = add("blank_circuit_board", new Item(properties("blank_circuit_board"))); + control_circuit = add("control_circuit", new Item(properties("control_circuit"))); + integrated_circuit = add("integrated_circuit", new Item(properties("integrated_circuit"))); + power_supply_unit = add("psu", new Item(properties("psu"))); + silicon_ingot = add("silicon_ingot", new Item(properties("silicon_ingot"))); + silicon_blend = add("silicon_mix", new Item(properties("silicon_mix"))); + solder_blend = add("solder_mix", new Item(properties("solder_mix"))); + solder = add("solder", new Item(properties("solder"))); + lithium_ingot = add("li_ingot", new Item(properties("li_ingot"))); + lithium_powder = add("li_powder", new Item(properties("li_powder"))); + lithium_nugget = add("li_nugget", new Item(properties("li_nugget"))); + sulfur_powder = add("sulfur_powder", new Item(properties("sulfur_powder"))); + petrolplastic_ingot = add("petrolplastic_ingot", new Item(properties("petrolplastic_ingot"))); + lead_acid_battery = add("lead_acid_battery", new BatteryItem(Power.LEAD_ACID_BATTERY_CAPACITY, properties("lead_acid_battery"))); + nickel_hydride_battery = add("nickel_hydride_battery", new BatteryItem(Power.NICKEL_HYDRIDE_BATTERY_CAPACITY, properties("nickel_hydride_battery"))); + alkaline_battery = add("alkaline_battery", new BatteryItem(Power.ALKALINE_BATTERY_CAPACITY, properties("alkaline_battery"))); + lithium_battery = add("lithium_battery", new BatteryItem(Power.LITHIUM_BATTERY_CAPACITY, properties("lithium_battery"))); initialized = true; } - private static Item.Properties properties() { return new Item.Properties(); } + private static Item.Properties properties(String id) { return new Item.Properties().setId(zone.moddev.mc.baseelectric.util.RegistryIds.item(id)); } private static Item add(String id, Item item) { allItems.put(id, item); return item; @@ -74,7 +74,7 @@ private static Item add(String id, Item item) { event.register(ForgeRegistries.Keys.ITEMS, registry -> { constructItems(); allItems.forEach((id, item) -> - registry.register(ResourceLocation.fromNamespaceAndPath(ElectricAdvantage.MODID, id), ItemGroups.show(item))); + registry.register(Identifier.fromNamespaceAndPath(ElectricAdvantage.MODID, id), ItemGroups.show(item))); }); } diff --git a/src/main/java/zone/moddev/mc/baseelectric/init/OreSpawnWorldGen.java b/src/main/java/zone/moddev/mc/baseelectric/init/OreSpawnWorldGen.java index 7be34361..1e6a0045 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/init/OreSpawnWorldGen.java +++ b/src/main/java/zone/moddev/mc/baseelectric/init/OreSpawnWorldGen.java @@ -3,7 +3,7 @@ import java.nio.file.Files; import java.nio.file.Path; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraftforge.fml.ModList; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.orespawn.api.GeologyFamily; @@ -13,13 +13,13 @@ /** Registers ElectricAdvantage's visible fallback mineral rules with OreSpawn 4. */ public final class OreSpawnWorldGen { - public static final ResourceLocation LITHIUM_ORE = - ResourceLocation.fromNamespaceAndPath(ElectricAdvantage.MODID, "ore/lithium"); - public static final ResourceLocation SULFUR_ORE = - ResourceLocation.fromNamespaceAndPath(ElectricAdvantage.MODID, "ore/sulfur"); - private static final ResourceLocation OVERWORLD = ResourceLocation.fromNamespaceAndPath("minecraft", "overworld"); - private static final ResourceLocation STONE = ResourceLocation.fromNamespaceAndPath("minecraft", "stone"); - private static final ResourceLocation STONE_TAG = ResourceLocation.fromNamespaceAndPath("forge", "stone"); + public static final Identifier LITHIUM_ORE = + Identifier.fromNamespaceAndPath(ElectricAdvantage.MODID, "ore/lithium"); + public static final Identifier SULFUR_ORE = + Identifier.fromNamespaceAndPath(ElectricAdvantage.MODID, "ore/sulfur"); + private static final Identifier OVERWORLD = Identifier.fromNamespaceAndPath("minecraft", "overworld"); + private static final Identifier STONE = Identifier.fromNamespaceAndPath("minecraft", "stone"); + private static final Identifier STONE_TAG = Identifier.fromNamespaceAndPath("forge", "stone"); private OreSpawnWorldGen() { } @@ -46,7 +46,7 @@ static WorldgenProvider createProvider(boolean mineralogyLoaded, boolean baseMin boolean electricSulfurEnabled = !mineralogyLoaded && !baseMineralsLoaded; boolean electricLithiumEnabled = !baseMineralsLoaded; return WorldgenProvider.builder(ElectricAdvantage.MODID, 1) - .ore(LITHIUM_ORE, ResourceLocation.fromNamespaceAndPath(ElectricAdvantage.MODID, "li_ore"), ore -> ore + .ore(LITHIUM_ORE, Identifier.fromNamespaceAndPath(ElectricAdvantage.MODID, "li_ore"), ore -> ore .enabled(electricLithiumEnabled) .retrogen(false) .dimension(OVERWORLD, dimension -> addHosts(dimension @@ -55,7 +55,7 @@ static WorldgenProvider createProvider(boolean mineralogyLoaded, boolean baseMin .attempts(0.125D) .quantityRange(6, 9) .pattern(OrePattern.DEFAULT)))) - .ore(SULFUR_ORE, ResourceLocation.fromNamespaceAndPath(ElectricAdvantage.MODID, "sulfur_ore"), ore -> ore + .ore(SULFUR_ORE, Identifier.fromNamespaceAndPath(ElectricAdvantage.MODID, "sulfur_ore"), ore -> ore .enabled(electricSulfurEnabled) .retrogen(false) .dimension(OVERWORLD, dimension -> addHosts(dimension diff --git a/src/main/java/zone/moddev/mc/baseelectric/init/Power.java b/src/main/java/zone/moddev/mc/baseelectric/init/Power.java index f0271dc5..582428cb 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/init/Power.java +++ b/src/main/java/zone/moddev/mc/baseelectric/init/Power.java @@ -4,7 +4,7 @@ import net.minecraft.world.damagesource.DamageType; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.world.level.Level; import cyano.poweradvantage.api.ConduitType; import zone.moddev.mc.baseelectric.ElectricAdvantage; @@ -32,10 +32,10 @@ public abstract class Power { public static final ResourceKey PROPELLER_DAMAGE = damageType("propeller"); private static ResourceKey damageType(String id) { - return ResourceKey.create(Registries.DAMAGE_TYPE, ResourceLocation.fromNamespaceAndPath(ElectricAdvantage.MODID, id)); + return ResourceKey.create(Registries.DAMAGE_TYPE, Identifier.fromNamespaceAndPath(ElectricAdvantage.MODID, id)); } public static DamageSource damageSource(Level level, ResourceKey type) { - return new DamageSource(level.registryAccess().registryOrThrow(Registries.DAMAGE_TYPE).getHolderOrThrow(type)); + return new DamageSource(level.registryAccess().lookupOrThrow(Registries.DAMAGE_TYPE).getOrThrow(type)); } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/init/Villages.java b/src/main/java/zone/moddev/mc/baseelectric/init/Villages.java index 6a60e317..59add056 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/init/Villages.java +++ b/src/main/java/zone/moddev/mc/baseelectric/init/Villages.java @@ -1,13 +1,12 @@ package zone.moddev.mc.baseelectric.init; import java.util.List; -import net.minecraft.world.entity.npc.VillagerProfession; -import net.minecraft.world.entity.npc.VillagerTrades; +import net.minecraft.world.entity.npc.villager.VillagerProfession; +import net.minecraft.world.entity.npc.villager.VillagerTrades; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.trading.MerchantOffer; import net.minecraft.world.item.trading.ItemCost; -import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.village.VillagerTradesEvent; /** Adds the historical librarian offers through the native profession trade event. */ @@ -18,7 +17,7 @@ private Villages() {} public static synchronized void init() { if (initialized) return; - MinecraftForge.EVENT_BUS.addListener(Villages::addTrades); + VillagerTradesEvent.BUS.addListener(Villages::addTrades); initialized = true; } @@ -35,7 +34,7 @@ public static void addTrades(VillagerTradesEvent event) { } static VillagerTrades.ItemListing sell(Item item, int minimumPrice, int maximumPrice) { - return (villager, random) -> { + return (level, villager, random) -> { int price = minimumPrice + random.nextInt(maximumPrice - minimumPrice + 1); int emeralds = price < 0 ? 1 : price; int count = price < 0 ? -price : 1; diff --git a/src/main/java/zone/moddev/mc/baseelectric/items/BatteryItem.java b/src/main/java/zone/moddev/mc/baseelectric/items/BatteryItem.java index fe30fa2b..e8b1c5d5 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/items/BatteryItem.java +++ b/src/main/java/zone/moddev/mc/baseelectric/items/BatteryItem.java @@ -33,9 +33,8 @@ public float getEnergy(ItemStack stack) { if (!(stack.getItem() instanceof BatteryItem battery)) return 0; // Vanilla moves unknown 1.20.1 item tags to CUSTOM_DATA on world upgrade. CustomData data = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY); - if (!data.contains("energy")) return battery.capacity; CompoundTag tag = data.copyTag(); - return tag.contains("energy", Tag.TAG_ANY_NUMERIC) ? tag.getFloat("energy") : battery.capacity; + return (tag.get("energy") instanceof net.minecraft.nbt.NumericTag) ? tag.getFloatOr("energy", 0F) : battery.capacity; } @Override public void setEnergy(ItemStack stack, float energy){ @@ -74,15 +73,20 @@ public ConduitType getEnergyType(){ } @Override - public void appendHoverText(ItemStack stack, TooltipContext context, List list, TooltipFlag flag){ - super.appendHoverText(stack, context, list, flag); + public void appendHoverText(ItemStack stack, TooltipContext context, + net.minecraft.world.item.component.TooltipDisplay display, java.util.function.Consumer list, TooltipFlag flag){ + super.appendHoverText(stack, context, display, list, flag); float max = getMaxEnergy(stack); if(max <= 0) return; // not a battery! float e = getEnergy(stack); - list.add(Component.literal(nf.format(100 * e / max) + "% ") + list.accept(Component.literal(nf.format(100 * e / max) + "% ") .append(Component.translatable("tooltip.battery.charge"))); - list.add(Component.literal("(" + nf.format(max) + "kJ ") + list.accept(Component.literal("(" + nf.format(max) + "kJ ") .append(Component.translatable("tooltip.battery.capacity")) .append(")")); } + + public void appendHoverText(ItemStack stack, TooltipContext context, List list, TooltipFlag flag) { + appendHoverText(stack, context, net.minecraft.world.item.component.TooltipDisplay.DEFAULT, list::add, flag); + } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricBatteryArrayBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricBatteryArrayBlock.java index 64e277d7..0ee5a631 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricBatteryArrayBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricBatteryArrayBlock.java @@ -6,7 +6,7 @@ public class ElectricBatteryArrayBlock extends ElectricGeneratorBlock { public ElectricBatteryArrayBlock(){ - super(); + super(machineProperties(0.75F).setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("electric_battery_array"))); } @Override diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricCrusherBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricCrusherBlock.java index 893429fd..b6d2c6de 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricCrusherBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricCrusherBlock.java @@ -5,7 +5,7 @@ public class ElectricCrusherBlock extends ElectricMachineBlock{ // NOTE: If a block's meta value goes above 0xF, then the block turns into a different block when it state changes public ElectricCrusherBlock(){ - super(); + super(machineProperties(0.75F).setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("electric_crusher"))); } @Override diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricCrusherTileEntity.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricCrusherTileEntity.java index 4dae2d81..ba200fcf 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricCrusherTileEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricCrusherTileEntity.java @@ -110,9 +110,9 @@ protected void saveTo(CompoundTag tagRoot) { @Override protected void loadFrom(CompoundTag tagRoot) { - ListTag times = tagRoot.getList("smashTime", 2); + ListTag times = tagRoot.getList("smashTime").filter(list -> list.stream().allMatch(entry -> entry.getId() == 2)).orElseGet(net.minecraft.nbt.ListTag::new); for(int i = 0; i < numberOfInputSlots() && i < times.size(); i++){ - smashTime[i] = ((ShortTag)times.get(i)).getAsShort(); + smashTime[i] = ((ShortTag)times.get(i)).shortValue(); } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricDrillBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricDrillBlock.java index 28b21230..25d8c437 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricDrillBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricDrillBlock.java @@ -14,7 +14,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.core.component.DataComponents; import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.entity.BlockEntity; @@ -27,13 +27,13 @@ import zone.moddev.mc.basepower.conduitnetwork.ConduitRegistry; public class ElectricDrillBlock extends GUIBlock implements ITypedConduit { - public static final DirectionProperty FACING = BlockStateProperties.FACING; + public static final EnumProperty FACING = BlockStateProperties.FACING; public static final BooleanProperty ACTIVE = BooleanProperty.create("active"); private final ConduitType[] types = {Power.ELECTRIC_POWER}; public ElectricDrillBlock() { - super(machineProperties(0.75F)); + super(machineProperties(0.75F).setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("electric_drill"))); registerDefaultState(getStateDefinition().any() .setValue(ACTIVE, false) .setValue(FACING, Direction.DOWN)); @@ -58,17 +58,10 @@ public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldS } @Override - public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { - if (state.getBlock() != newState.getBlock()) { - ConduitRegistry.getInstance().conduitBlockRemovedEvent( - world, pos, Power.ELECTRIC_POWER); - BlockEntity tile = world.getBlockEntity(pos); - if (tile instanceof Container) { - Containers.dropContents(world, pos, (Container) tile); - world.updateNeighbourForOutputSignal(pos, this); - } - } - super.onRemove(state, world, pos, newState, isMoving); + public void affectNeighborsAfterRemoval(BlockState state, net.minecraft.server.level.ServerLevel world, BlockPos pos, boolean isMoving) { + ConduitRegistry.getInstance().conduitBlockRemovedEvent(world, pos, Power.ELECTRIC_POWER); + world.updateNeighbourForOutputSignal(pos, this); + super.affectNeighborsAfterRemoval(state, world, pos, isMoving); } @Override diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricDrillTileEntity.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricDrillTileEntity.java index 8b56ea08..ffef8939 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricDrillTileEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricDrillTileEntity.java @@ -21,8 +21,6 @@ import net.minecraft.util.Mth; import net.minecraft.world.level.Level; import net.minecraft.server.level.ServerLevel; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import java.util.ArrayList; import java.util.Arrays; @@ -153,7 +151,9 @@ private boolean followTrack(){ w.setBlock(nextPos, w.getBlockState(getBlockPos()), 2); ElectricDrillTileEntity te = (ElectricDrillTileEntity)w.getBlockEntity(nextPos); CompoundTag dataTransfer = saveWithoutMetadata(w.registryAccess()); - te.loadWithComponents(dataTransfer, w.registryAccess()); + try (var problems = new net.minecraft.util.ProblemReporter.ScopedCollector(org.slf4j.LoggerFactory.getLogger("baseelectric"))) { + te.loadWithComponents(net.minecraft.world.level.storage.TagValueInput.create(problems, w.registryAccess(), dataTransfer)); + } te.clearRemoved(); te.subtractEnergy(ENERGY_COST_MOVE, getEnergyType()); te.setChanged(); @@ -290,7 +290,7 @@ public void onDataFieldUpdate() { List victims = getLevel().getEntitiesOfClass(LivingEntity.class, beamArea); for(Entity e : victims){ e.igniteForSeconds(3); - e.hurt(Power.damageSource(getLevel(), Power.LASER_DAMAGE), 2f); + e.hurtServer((net.minecraft.server.level.ServerLevel) getLevel(), Power.damageSource(getLevel(), Power.LASER_DAMAGE), 2f); } } } @@ -337,7 +337,7 @@ private void restoreTargetBlock(){ return; } for(int i = 0; i < targets.length; i++){ - if(!savedTargetStates.getCompound(i).equals(NbtUtils.writeBlockState(getLevel().getBlockState(targets[i])))){ + if(!savedTargetStates.getCompoundOrEmpty(i).equals(NbtUtils.writeBlockState(getLevel().getBlockState(targets[i])))){ untargetBlock(); return; } @@ -499,14 +499,14 @@ protected void saveTo(CompoundTag tagRoot) { @Override protected void loadFrom(CompoundTag tagRoot) { untargetBlock(); - if(tagRoot.contains("progress", 99)){ - progress = tagRoot.getShort("progress"); + if((tagRoot.get("progress") instanceof net.minecraft.nbt.NumericTag)){ + progress = tagRoot.getShortOr("progress", (short) 0); } - if(tagRoot.contains("targetX", 99) && tagRoot.contains("targetY", 99) && tagRoot.contains("targetZ", 99)){ - int x = tagRoot.getInt("targetX"); - int y = tagRoot.getInt("targetY"); - int z = tagRoot.getInt("targetZ"); - savedTargetStates = tagRoot.contains("TargetStates", 9) ? tagRoot.getList("TargetStates", 10).copy() : null; + if((tagRoot.get("targetX") instanceof net.minecraft.nbt.NumericTag) && (tagRoot.get("targetY") instanceof net.minecraft.nbt.NumericTag) && (tagRoot.get("targetZ") instanceof net.minecraft.nbt.NumericTag)){ + int x = tagRoot.getIntOr("targetX", 0); + int y = tagRoot.getIntOr("targetY", 0); + int z = tagRoot.getIntOr("targetZ", 0); + savedTargetStates = (tagRoot.get("TargetStates") instanceof net.minecraft.nbt.ListTag) ? tagRoot.getList("TargetStates").filter(list -> list.stream().allMatch(entry -> entry.getId() == 10)).orElseGet(net.minecraft.nbt.ListTag::new).copy() : null; // Note: world object for tile entities is set AFTER loading them from NBT if(getLevel() == null){ this.deferredTargetBlock(new BlockPos(x,y,z)); @@ -543,7 +543,6 @@ public boolean isActive(){ // Helps with laser rendering final private int renderRange = MAX_RANGE * 2; - @OnlyIn(Dist.CLIENT) public AABB getRenderBoundingBox() { return new AABB(getBlockPos()).inflate(renderRange); diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFabricatorBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFabricatorBlock.java index 891ba1af..3b1da28d 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFabricatorBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFabricatorBlock.java @@ -3,6 +3,9 @@ import net.minecraft.world.level.Level; public class ElectricFabricatorBlock extends ElectricMachineBlock{ + public ElectricFabricatorBlock() { + super(machineProperties(0.75F).setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("electric_fabricator"))); + } @Override public ElectricMachineTileEntity newBlockEntity(net.minecraft.core.BlockPos pos, net.minecraft.world.level.block.state.BlockState state) { diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFabricatorTileEntity.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFabricatorTileEntity.java index 846dbae5..f5d0cab6 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFabricatorTileEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFabricatorTileEntity.java @@ -167,11 +167,11 @@ protected void saveTo(CompoundTag tagRoot) { @Override protected void loadFrom(CompoundTag tagRoot) { - if(tagRoot.contains("progress", 99)){ - this.progress = tagRoot.getShort("progress"); + if((tagRoot.get("progress") instanceof net.minecraft.nbt.NumericTag)){ + this.progress = tagRoot.getShortOr("progress", (short) 0); } - if(tagRoot.contains("FSM", 99)){ - this.state = FSM.values()[tagRoot.getByte("FSM")]; + if((tagRoot.get("FSM") instanceof net.minecraft.nbt.NumericTag)){ + this.state = FSM.values()[tagRoot.getByteOr("FSM", (byte) 0)]; } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFurnaceBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFurnaceBlock.java index aca7dbe4..412dca2d 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFurnaceBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFurnaceBlock.java @@ -5,7 +5,7 @@ public class ElectricFurnaceBlock extends ElectricMachineBlock{ public ElectricFurnaceBlock(){ - super(); + super(machineProperties(0.75F).setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("electric_furnace"))); } @Override diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFurnaceTileEntity.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFurnaceTileEntity.java index 5214a5bd..27f8dfc9 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFurnaceTileEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricFurnaceTileEntity.java @@ -106,9 +106,9 @@ protected void saveTo(CompoundTag tagRoot) { @Override protected void loadFrom(CompoundTag tagRoot) { - ListTag burnTimes = tagRoot.getList("cookTime", 2); + ListTag burnTimes = tagRoot.getList("cookTime").filter(list -> list.stream().allMatch(entry -> entry.getId() == 2)).orElseGet(net.minecraft.nbt.ListTag::new); for(int i = 0; i < numberOfInputSlots() && i < burnTimes.size(); i++){ - burnTime[i] = ((ShortTag)burnTimes.get(i)).getAsShort(); + burnTime[i] = ((ShortTag)burnTimes.get(i)).shortValue(); } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricGeneratorBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricGeneratorBlock.java index e00141d9..c5179092 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricGeneratorBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricGeneratorBlock.java @@ -65,16 +65,10 @@ public boolean hasAnalogOutputSignal(BlockState state) { } @Override - public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { - if (state.getBlock() != newState.getBlock()) { - BlockEntity tile = world.getBlockEntity(pos); - if (tile instanceof Container) { - Containers.dropContents(world, pos, (Container) tile); - ((Container) tile).clearContent(); - world.updateNeighbourForOutputSignal(pos, this); - } - } - super.onRemove(state, world, pos, newState, isMoving); + public void affectNeighborsAfterRemoval(BlockState state, net.minecraft.server.level.ServerLevel world, BlockPos pos, boolean isMoving) { + // Native BlockEntity.preRemoveSideEffects owns the inventory drop. + world.updateNeighbourForOutputSignal(pos, this); + super.affectNeighborsAfterRemoval(state, world, pos, isMoving); } @Override diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricGeneratorTileEntity.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricGeneratorTileEntity.java index 2c204533..a9348173 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricGeneratorTileEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricGeneratorTileEntity.java @@ -58,7 +58,7 @@ public void powerUpdate(){ protected boolean hasRedstoneSignal(){ // Generators can check the interlock before their first power-update refresh. - if(!redstoneInitialized && getLevel() != null && !getLevel().isClientSide){ + if(!redstoneInitialized && getLevel() != null && !getLevel().isClientSide()){ redstone = getLevel().hasNeighborSignal(getBlockPos()); redstoneInitialized = true; } @@ -163,15 +163,17 @@ public int getComparatorOutput(){ @Override - protected void saveAdditional(CompoundTag tagRoot, HolderLookup.Provider registries){ - super.saveAdditional(tagRoot, registries); + protected void saveAdditional(net.minecraft.world.level.storage.ValueOutput output){ + super.saveAdditional(output); + CompoundTag tagRoot = new CompoundTag(); saveTo(tagRoot); + output.store(zone.moddev.mc.baseelectric.util.LegacyNbt.ROOT, tagRoot); } @Override - protected void loadAdditional(CompoundTag tagRoot, HolderLookup.Provider registries){ - super.loadAdditional(tagRoot, registries); - loadFrom(tagRoot); + protected void loadAdditional(net.minecraft.world.level.storage.ValueInput input){ + super.loadAdditional(input); + loadFrom(input.read(zone.moddev.mc.baseelectric.util.LegacyNbt.ROOT).orElseGet(CompoundTag::new)); } protected abstract void saveTo(CompoundTag tagRoot); diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricMachineBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricMachineBlock.java index a0bbff0e..b33414e8 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricMachineBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricMachineBlock.java @@ -94,16 +94,10 @@ public boolean hasAnalogOutputSignal(BlockState state) { } @Override - public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) { - if (state.getBlock() != newState.getBlock()) { - BlockEntity tile = world.getBlockEntity(pos); - if (tile instanceof Container) { - Containers.dropContents(world, pos, (Container) tile); - ((Container) tile).clearContent(); - world.updateNeighbourForOutputSignal(pos, this); - } - } - super.onRemove(state, world, pos, newState, isMoving); + public void affectNeighborsAfterRemoval(BlockState state, net.minecraft.server.level.ServerLevel world, BlockPos pos, boolean isMoving) { + // Native BlockEntity.preRemoveSideEffects owns the inventory drop. + world.updateNeighbourForOutputSignal(pos, this); + super.affectNeighborsAfterRemoval(state, world, pos, isMoving); } @Override diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricMachineTileEntity.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricMachineTileEntity.java index d02f2c69..a29d4017 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricMachineTileEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricMachineTileEntity.java @@ -96,7 +96,7 @@ public void powerUpdate(){ protected boolean hasRedstoneSignal(){ // tickUpdate runs before the first scheduled powerUpdate after loading. - if(!redstoneInitialized && getLevel() != null && !getLevel().isClientSide){ + if(!redstoneInitialized && getLevel() != null && !getLevel().isClientSide()){ redstone = getLevel().hasNeighborSignal(getBlockPos()); redstoneInitialized = true; } @@ -219,14 +219,17 @@ protected static boolean areItemStacksEqualNullable(ItemStack left, ItemStack ri protected ItemStack getSmeltingResult(ItemStack input) { if (isEmptyStack(input) || getLevel() == null) return ItemStack.EMPTY; SingleRecipeInput inventory = new SingleRecipeInput(input); - return getLevel().getRecipeManager().getRecipeFor(RecipeType.SMELTING, inventory, getLevel()) + if (!(getLevel() instanceof net.minecraft.server.level.ServerLevel server)) return ItemStack.EMPTY; + return server.recipeAccess().getRecipeFor(RecipeType.SMELTING, inventory, getLevel()) .map(recipe -> recipe.value().assemble(inventory, getLevel().registryAccess())).orElse(ItemStack.EMPTY); } @Override - protected void saveAdditional(CompoundTag tagRoot, HolderLookup.Provider registries){ - super.saveAdditional(tagRoot, registries); + protected void saveAdditional(net.minecraft.world.level.storage.ValueOutput output){ + super.saveAdditional(output); + CompoundTag tagRoot = new CompoundTag(); saveTo(tagRoot); + output.store(zone.moddev.mc.baseelectric.util.LegacyNbt.ROOT, tagRoot); } @Override @@ -235,9 +238,9 @@ public CompoundTag getUpdateTag(HolderLookup.Provider registries) { } @Override - protected void loadAdditional(CompoundTag tagRoot, HolderLookup.Provider registries){ - super.loadAdditional(tagRoot, registries); - loadFrom(tagRoot); + protected void loadAdditional(net.minecraft.world.level.storage.ValueInput input){ + super.loadAdditional(input); + loadFrom(input.read(zone.moddev.mc.baseelectric.util.LegacyNbt.ROOT).orElseGet(CompoundTag::new)); } protected abstract void saveTo(CompoundTag tagRoot); diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalSound.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalSound.java index b702cbea..ffcd8e2e 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalSound.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalSound.java @@ -15,7 +15,7 @@ final class ElectricOperationalSound { private ElectricOperationalSound() {} static void broadcast(Level level, double x, double y, double z, SoundEvent sound, float volume, float pitch) { - if (level.isClientSide) return; + if (level.isClientSide()) return; final double range = 16; AABB bounds = new AABB(x - range, y - range, z - range, x + range, y + range, z + range); ClientboundSoundPacket packet = null; diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricOvenBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricOvenBlock.java index a0c4ed43..6932c3a8 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricOvenBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricOvenBlock.java @@ -5,7 +5,7 @@ public class ElectricOvenBlock extends ElectricMachineBlock{ public ElectricOvenBlock(){ - super(); + super(machineProperties(0.75F).setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("electric_oven"))); } @Override diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricOvenTileEntity.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricOvenTileEntity.java index f4616674..a409d368 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricOvenTileEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricOvenTileEntity.java @@ -80,8 +80,8 @@ protected void saveTo(CompoundTag tagRoot) { @Override protected void loadFrom(CompoundTag tagRoot) { - if(tagRoot.contains("cookTime", 99)){ - progress = tagRoot.getShort("cookTime"); + if((tagRoot.get("cookTime") instanceof net.minecraft.nbt.NumericTag)){ + progress = tagRoot.getShortOr("cookTime", (short) 0); } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricPumpBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricPumpBlock.java index 9030fdb6..471d53c7 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricPumpBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricPumpBlock.java @@ -12,6 +12,9 @@ import net.minecraft.world.level.Level; public class ElectricPumpBlock extends ElectricMachineBlock{ + public ElectricPumpBlock() { + super(machineProperties(0.75F).setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("electric_pump"))); + } @Override public ElectricMachineTileEntity newBlockEntity(net.minecraft.core.BlockPos pos, net.minecraft.world.level.block.state.BlockState state) { @@ -24,9 +27,9 @@ public ElectricMachineTileEntity newBlockEntity(net.minecraft.core.BlockPos pos, * This method is called whenever the block is placed into the world */ @Override - public void onRemove(BlockState state, Level w, BlockPos coord, BlockState newState, boolean isMoving) { - if (state.getBlock() != newState.getBlock()) destroyPipe(w, coord); - super.onRemove(state, w, coord, newState, isMoving); + public void affectNeighborsAfterRemoval(BlockState state, net.minecraft.server.level.ServerLevel w, BlockPos coord, boolean isMoving) { + destroyPipe(w, coord); + super.affectNeighborsAfterRemoval(state, w, coord, isMoving); } /** * This method is called when the block is destroyed by an explosion. @@ -39,7 +42,7 @@ public void wasExploded(Level w, BlockPos coord, Explosion boom){ private void destroyPipe(Level w, BlockPos coord) { - if(w.isClientSide) return; + if(w.isClientSide()) return; // destroy connected drill bits BlockPos c = coord.below(); while(c.getY() > 0 && w.getBlockState(c).getBlock() == Blocks.pump_pipe_electric){ diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricPumpTileEntity.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricPumpTileEntity.java index a1b91b8b..6cddf63f 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricPumpTileEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricPumpTileEntity.java @@ -266,17 +266,17 @@ public void saveTo(final CompoundTag tagRoot) { */ @Override public void loadFrom(final CompoundTag tagRoot) { - if (tagRoot.contains("Tank", 10)) { - CompoundTag tankTag = tagRoot.getCompound("Tank"); + if ((tagRoot.get("Tank") instanceof net.minecraft.nbt.CompoundTag)) { + CompoundTag tankTag = tagRoot.getCompoundOrEmpty("Tank"); getTank().readFromNBT(tankTag); - if(tankTag.contains("Empty", 1)){ + if((tankTag.get("Empty") instanceof net.minecraft.nbt.ByteTag)){ // empty the tank if NBT says its empty (not default behavior of Tank.readFromNBT(...) ) getTank().setFluid(null); } } - if (tagRoot.contains("NextPump", 99)) { - this.timeUntilNextPump = tagRoot.getByte("NextPump"); + if ((tagRoot.get("NextPump") instanceof net.minecraft.nbt.NumericTag)) { + this.timeUntilNextPump = tagRoot.getByteOr("NextPump", (byte) 0); } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricStillBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricStillBlock.java index 44888562..e8e01143 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricStillBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricStillBlock.java @@ -7,6 +7,9 @@ import net.minecraft.world.level.Level; public class ElectricStillBlock extends ElectricMachineBlock{ + public ElectricStillBlock() { + super(machineProperties(0.75F).setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("electric_still"))); + } @Override public ElectricMachineTileEntity newBlockEntity(net.minecraft.core.BlockPos pos, net.minecraft.world.level.block.state.BlockState state) { diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricStillTileEntity.java b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricStillTileEntity.java index c07fe164..8c6d6d89 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricStillTileEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/ElectricStillTileEntity.java @@ -198,19 +198,19 @@ public void saveTo(final CompoundTag tagRoot) { */ @Override public void loadFrom(final CompoundTag tagRoot) { - if (tagRoot.contains("TankOut", 10)) { - CompoundTag tankTag = tagRoot.getCompound("TankOut"); + if ((tagRoot.get("TankOut") instanceof net.minecraft.nbt.CompoundTag)) { + CompoundTag tankTag = tagRoot.getCompoundOrEmpty("TankOut"); getOutputTank().readFromNBT(tankTag); - if(tankTag.contains("Empty", 1)){ + if((tankTag.get("Empty") instanceof net.minecraft.nbt.ByteTag)){ // empty the tank if NBT says its empty (not default behavior of Tank.readFromNBT(...) ) getOutputTank().setFluid(null); } } - if (tagRoot.contains("TankIn", 10)) { - CompoundTag tankTag = tagRoot.getCompound("TankIn"); + if ((tagRoot.get("TankIn") instanceof net.minecraft.nbt.CompoundTag)) { + CompoundTag tankTag = tagRoot.getCompoundOrEmpty("TankIn"); getInputTank().readFromNBT(tankTag); - if(tankTag.contains("Empty", 1)){ + if((tankTag.get("Empty") instanceof net.minecraft.nbt.ByteTag)){ // empty the tank if NBT says its empty (not default behavior of Tank.readFromNBT(...) ) getInputTank().setFluid(null); } diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberBlock.java index dd429f67..36992878 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberBlock.java @@ -6,7 +6,7 @@ public class GrowthChamberBlock extends ElectricMachineBlock{ public GrowthChamberBlock(){ - super(machineProperties(0.75f), Power.GROWTHCHAMBER_POWER); + super(machineProperties(0.75f).setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("growth_chamber")), Power.GROWTHCHAMBER_POWER); } @Override diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberControllerBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberControllerBlock.java index 34367c49..3f189adb 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberControllerBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberControllerBlock.java @@ -20,7 +20,7 @@ public class GrowthChamberControllerBlock extends cyano.poweradvantage.api.simpl public GrowthChamberControllerBlock() { - super(machineProperties(0.75f), + super(machineProperties(0.75f).setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("growth_chamber_controller")), Power.GROWTHCHAMBER_POWER, Power.ELECTRIC_POWER, Fluids.fluidConduit_general); } diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberControllerTileEntity.java b/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberControllerTileEntity.java index f9d97483..4cd4c127 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberControllerTileEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberControllerTileEntity.java @@ -20,10 +20,10 @@ import net.minecraft.core.registries.Registries; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; public class GrowthChamberControllerTileEntity extends cyano.poweradvantage.api.simple.TileEntitySimplePowerMachine implements LegacyFluidHandler{ - private static final TagKey DIRT_TAG = TagKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath("forge", "dirt")); + private static final TagKey DIRT_TAG = TagKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath("forge", "dirt")); static final float ELECTRICITY_PER_UNIT = 8f; @@ -191,33 +191,36 @@ public void onDataFieldUpdate() { /** * Handles data saving and loading - * @param tagRoot An NBT tag + * @param output Native machine data output */ @Override - protected void saveAdditional(final CompoundTag tagRoot, HolderLookup.Provider registries) { - super.saveAdditional(tagRoot, registries); + protected void saveAdditional(net.minecraft.world.level.storage.ValueOutput output) { + super.saveAdditional(output); + CompoundTag tagRoot = new CompoundTag(); CompoundTag tankTag = new CompoundTag(); this.getTank().writeToNBT(tankTag); tagRoot.put("Tank", tankTag); tagRoot.putFloat("soil", soil); + output.store(zone.moddev.mc.baseelectric.util.LegacyNbt.ROOT, tagRoot); } /** * Handles data saving and loading - * @param tagRoot An NBT tag + * @param input Native machine data input */ @Override - protected void loadAdditional(final CompoundTag tagRoot, HolderLookup.Provider registries) { - super.loadAdditional(tagRoot, registries); - if (tagRoot.contains("Tank", 10)) { - CompoundTag tankTag = tagRoot.getCompound("Tank"); + protected void loadAdditional(net.minecraft.world.level.storage.ValueInput input) { + super.loadAdditional(input); + CompoundTag tagRoot = input.read(zone.moddev.mc.baseelectric.util.LegacyNbt.ROOT).orElseGet(CompoundTag::new); + if ((tagRoot.get("Tank") instanceof net.minecraft.nbt.CompoundTag)) { + CompoundTag tankTag = tagRoot.getCompoundOrEmpty("Tank"); getTank().readFromNBT(tankTag); - if(tankTag.contains("Empty", 1)){ + if((tankTag.get("Empty") instanceof net.minecraft.nbt.ByteTag)){ // empty the tank if NBT says its empty (not default behavior of Tank.readFromNBT(...) ) getTank().setFluid(null); } } - if(tagRoot.contains("soil", 99)){ - this.soil = tagRoot.getFloat("soil"); + if((tagRoot.get("soil") instanceof net.minecraft.nbt.NumericTag)){ + this.soil = tagRoot.getFloatOr("soil", 0F); } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberTileEntity.java b/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberTileEntity.java index 0ea93d96..26fbf923 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberTileEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/GrowthChamberTileEntity.java @@ -176,10 +176,10 @@ protected void loadFrom(CompoundTag tagRoot) { Arrays.fill(progression, 0); Arrays.fill(progressionMax, 0); oldInventory = null; - pendingGrowth = tagRoot.contains("growth", 7) - ? Arrays.copyOf(tagRoot.getByteArray("growth"), GROWTH_AREA) : null; - if(tagRoot.contains("prog", 11)){ - int[] saved = tagRoot.getIntArray("prog"); + pendingGrowth = (tagRoot.get("growth") instanceof net.minecraft.nbt.ByteArrayTag) + ? Arrays.copyOf(tagRoot.getByteArray("growth").orElseGet(() -> new byte[0]), GROWTH_AREA) : null; + if((tagRoot.get("prog") instanceof net.minecraft.nbt.IntArrayTag)){ + int[] saved = tagRoot.getIntArray("prog").orElseGet(() -> new int[0]); System.arraycopy(saved, 0, progression, 0, Math.min(saved.length, progression.length)); } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/HydroelectricGeneratorBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/HydroelectricGeneratorBlock.java index 0b03e545..41690133 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/HydroelectricGeneratorBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/HydroelectricGeneratorBlock.java @@ -7,7 +7,7 @@ public class HydroelectricGeneratorBlock extends ElectricGeneratorBlock { public HydroelectricGeneratorBlock(){ - super(); + super(machineProperties(0.75F).setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("hydroelectric_generator"))); } @Override diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/HydroelectricGeneratorTileEntity.java b/src/main/java/zone/moddev/mc/baseelectric/machines/HydroelectricGeneratorTileEntity.java index 6cba25c0..4e5e6e45 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/HydroelectricGeneratorTileEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/HydroelectricGeneratorTileEntity.java @@ -71,8 +71,8 @@ protected void saveTo(CompoundTag tagRoot) { @Override protected void loadFrom(CompoundTag tagRoot) { - if(tagRoot.contains("initDone", 1)){ - this.isInitialized = tagRoot.getBoolean("initDone"); + if((tagRoot.get("initDone") instanceof net.minecraft.nbt.ByteTag)){ + this.isInitialized = tagRoot.getBooleanOr("initDone", false); } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/LEDBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/LEDBlock.java index b8c2b2af..cd0effc1 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/LEDBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/LEDBlock.java @@ -20,7 +20,7 @@ public class LEDBlock extends ElectricConduitBlock implements EntityBlock { public static final BooleanProperty LIT = BooleanProperty.create("lit"); public LEDBlock() { - super(); + super("led_bar"); registerDefaultState(getStateDefinition().any() .setValue(WEST, false).setValue(DOWN, false).setValue(SOUTH, false) .setValue(EAST, false).setValue(UP, false).setValue(NORTH, false) diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/LaserTurretBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/LaserTurretBlock.java index 8b37e859..c152e5c6 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/LaserTurretBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/LaserTurretBlock.java @@ -23,7 +23,8 @@ public class LaserTurretBlock extends ElectricMachineBlock { // Evil laser turrets target players and not hostile mobs public final boolean evil; public LaserTurretBlock(boolean isEvil) { - super(machineProperties(5.0F).strength(5.0F, 100.0F)); + super(machineProperties(5.0F).strength(5.0F, 100.0F).setId( + zone.moddev.mc.baseelectric.util.RegistryIds.block(isEvil ? "laser_turret_evil" : "laser_turret"))); this.evil = isEvil; } diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/LaserTurretTileEntity.java b/src/main/java/zone/moddev/mc/baseelectric/machines/LaserTurretTileEntity.java index 4a9ca3ee..14014106 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/LaserTurretTileEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/LaserTurretTileEntity.java @@ -16,7 +16,7 @@ import net.minecraft.network.Connection; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.world.scores.Team; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.sounds.SoundEvent; import net.minecraft.core.BlockPos; import net.minecraft.world.phys.AABB; @@ -29,8 +29,6 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.registries.ForgeRegistries; import java.util.ArrayList; @@ -89,7 +87,7 @@ public class LaserTurretTileEntity extends ElectricMachineTileEntity{ public LaserTurretTileEntity(net.minecraft.core.BlockPos pos, net.minecraft.world.level.block.state.BlockState state){ super(zone.moddev.mc.baseelectric.init.Entities.LASER_TURRET, pos, state, "tile.baseelectric.laser_turret.name",MAX_BUFFER,0,0,0); SoundEvent soundEvent = ElectricAdvantage.INSTANCE == null ? SoundEvents.NOTE_BLOCK_BASS.value() - : ForgeRegistries.SOUND_EVENTS.getValue(ResourceLocation.parse(ElectricAdvantage.INSTANCE.LASER_SOUND)); + : ForgeRegistries.SOUND_EVENTS.getValue(Identifier.parse(ElectricAdvantage.INSTANCE.LASER_SOUND)); if(soundEvent == null){ LASER_SOUND = SoundEvents.ENDERMAN_TELEPORT; } else { @@ -109,7 +107,7 @@ public void tickUpdate(boolean b) { laserAttack--; } boolean isActive = isActive(); - if(w.isClientSide){ + if(w.isClientSide()){ // client-side only if(isActive){ if(targetLocked == false){ @@ -276,7 +274,8 @@ && rayIntersectsBoundingBox(origin,dir,v.getBoundingBox())){ private void hurtVictim(Entity e){ e.igniteForSeconds(BURN_TIME); if(e instanceof LivingEntity){ - ((LivingEntity)e).hurt(Power.damageSource(getLevel(), Power.LASER_DAMAGE), ATTACK_DAMAGE); + ((LivingEntity)e).hurtServer((net.minecraft.server.level.ServerLevel) getLevel(), + Power.damageSource(getLevel(), Power.LASER_DAMAGE), ATTACK_DAMAGE); BlockPos bp = e.blockPosition(); if(getLevel().isEmptyBlock(bp) && !getLevel().isEmptyBlock(bp.below())){ getLevel().setBlockAndUpdate(bp, Blocks.FIRE.defaultBlockState()); @@ -366,7 +365,7 @@ private static double min(double a, double b){ private void drawLaserLine() { // client-side only Level w = getLevel(); - if(w.isClientSide){ + if(w.isClientSide()){ this.laserBlastLength = getOpticPosition().distanceTo(calculateLaserTerminus()); } } @@ -514,9 +513,9 @@ public CompoundTag getUpdateTag(HolderLookup.Provider registries) { } @Override - public void handleUpdateTag(CompoundTag tag, HolderLookup.Provider registries) { + public void handleUpdateTag(net.minecraft.world.level.storage.ValueInput tag, HolderLookup.Provider registries) { super.handleUpdateTag(tag, registries); - readRenderSync(tag); + readRenderSync(tag.read(zone.moddev.mc.baseelectric.util.LegacyNbt.ROOT).orElseGet(CompoundTag::new)); } private void writeRenderSync(CompoundTag nbtTag) { @@ -540,28 +539,33 @@ private void writeRenderSync(CompoundTag nbtTag) { * Receives the network packet made by getDescriptionPacket() */ @Override + public void onDataPacket(Connection net, net.minecraft.world.level.storage.ValueInput data, HolderLookup.Provider registries) { + readRenderSync(data.read(zone.moddev.mc.baseelectric.util.LegacyNbt.ROOT).orElseGet(CompoundTag::new)); + } + + @Override public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket packet, HolderLookup.Provider registries) { readRenderSync(packet.getTag()); } private void readRenderSync(CompoundTag tag) { - if(tag.contains("lock", 1)){ - this.targetLocked = tag.getBoolean("lock"); - if(tag.contains("target", 10)){ - CompoundTag target = tag.getCompound("target"); - this.targetID = target.getInt("id"); + if((tag.get("lock") instanceof net.minecraft.nbt.ByteTag)){ + this.targetLocked = tag.getBooleanOr("lock", false); + if((tag.get("target") instanceof net.minecraft.nbt.CompoundTag)){ + CompoundTag target = tag.getCompoundOrEmpty("target"); + this.targetID = target.getIntOr("id", 0); Entity e = getLevel().getEntity(targetID); if(e != null){ this.lookAt(e); } else { - this.rotTargetYaw = target.getFloat("yaw"); - this.rotTargetPitch = target.getFloat("pitch"); + this.rotTargetYaw = target.getFloatOr("yaw", 0F); + this.rotTargetPitch = target.getFloatOr("pitch", 0F); } - this.laserAttack = target.getByte("attack"); + this.laserAttack = target.getByteOr("attack", (byte) 0); } } - if(tag.contains("energy", 99)){ - this.setEnergy(tag.getFloat("energy"),getEnergyType()); + if((tag.get("energy") instanceof net.minecraft.nbt.NumericTag)){ + this.setEnergy(tag.getFloatOr("energy", 0F),getEnergyType()); } } @@ -590,21 +594,21 @@ protected void saveTo(CompoundTag root) { @Override protected void loadFrom(CompoundTag root) { - if(root.contains("pitch", 99)){ - this.rotPitch = root.getFloat("pitch"); + if((root.get("pitch") instanceof net.minecraft.nbt.NumericTag)){ + this.rotPitch = root.getFloatOr("pitch", 0F); this.rotOldPitch = rotPitch; this.rotTargetPitch = rotPitch; } - if(root.contains("yaw", 99)){ - this.rotYaw = root.getFloat("yaw"); + if((root.get("yaw") instanceof net.minecraft.nbt.NumericTag)){ + this.rotYaw = root.getFloatOr("yaw", 0F); this.rotOldYaw = rotYaw; this.rotTargetYaw = rotYaw; } - if(root.contains("lock", 1)){ - targetLocked = root.getBoolean("lock"); + if((root.get("lock") instanceof net.minecraft.nbt.ByteTag)){ + targetLocked = root.getBooleanOr("lock", false); } - if(root.contains("team", 8)){ - String teamName = root.getString("team"); + if((root.get("team") instanceof net.minecraft.nbt.StringTag)){ + String teamName = root.getStringOr("team", ""); if(teamName.isEmpty()){ this.teamIdentity = null; }else{ @@ -612,8 +616,8 @@ protected void loadFrom(CompoundTag root) { } } - if(root.contains("player", 8)){ - playerOwner = root.getString("player"); + if((root.get("player") instanceof net.minecraft.nbt.StringTag)){ + playerOwner = root.getStringOr("player", ""); } } @@ -654,7 +658,6 @@ public int getComparatorOutput(){ // Helps with laser rendering final private int renderRange = ATTACK_RANGE * 2; - @OnlyIn(Dist.CLIENT) public AABB getRenderBoundingBox() { return new AABB(getBlockPos()).inflate(renderRange); diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/PhotovoltaicGeneratorBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/PhotovoltaicGeneratorBlock.java index f6d2f1cf..7cdf84d8 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/PhotovoltaicGeneratorBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/PhotovoltaicGeneratorBlock.java @@ -8,7 +8,8 @@ public class PhotovoltaicGeneratorBlock extends ElectricGeneratorBlock{ public PhotovoltaicGeneratorBlock(){ - super(net.minecraft.world.level.block.Block.Properties.of().mapColor(MapColor.STONE) + super(net.minecraft.world.level.block.Block.Properties.of().setId( + zone.moddev.mc.baseelectric.util.RegistryIds.block("photovoltaic_generator")).mapColor(MapColor.STONE) .forceSolidOn().strength(0.75F).sound(SoundType.GLASS).dynamicShape() .isRedstoneConductor((state, world, pos) -> true)); } diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/PlasticRefineryBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/PlasticRefineryBlock.java index 97e2d7e0..9d9219c4 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/PlasticRefineryBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/PlasticRefineryBlock.java @@ -6,6 +6,9 @@ import zone.moddev.mc.basepower.init.Fluids; public class PlasticRefineryBlock extends ElectricMachineBlock{ + public PlasticRefineryBlock() { + super(machineProperties(0.75F).setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("plastic_refinery"))); + } @Override public ElectricMachineTileEntity newBlockEntity(net.minecraft.core.BlockPos pos, net.minecraft.world.level.block.state.BlockState state) { diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/PlasticRefineryTileEntity.java b/src/main/java/zone/moddev/mc/baseelectric/machines/PlasticRefineryTileEntity.java index 0eddf244..ed3ccbc5 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/PlasticRefineryTileEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/PlasticRefineryTileEntity.java @@ -21,12 +21,12 @@ import net.minecraft.core.registries.Registries; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import java.util.List; public class PlasticRefineryTileEntity extends ElectricMachineTileEntity implements LegacyFluidHandler{ - private static final TagKey PLASTICS_TAG = TagKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath("forge", "plastics")); + private static final TagKey PLASTICS_TAG = TagKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath("forge", "plastics")); public static final float ENERGY_PER_TICK = 12f; @@ -114,13 +114,13 @@ protected void saveTo(CompoundTag tagRoot) { @Override protected void loadFrom(CompoundTag tagRoot) { - if(tagRoot.contains("progress", 99)){ - this.fabTime = tagRoot.getShort("progress"); + if((tagRoot.get("progress") instanceof net.minecraft.nbt.NumericTag)){ + this.fabTime = tagRoot.getShortOr("progress", (short) 0); } - if (tagRoot.contains("Tank", 10)) { - CompoundTag tankTag = tagRoot.getCompound("Tank"); + if ((tagRoot.get("Tank") instanceof net.minecraft.nbt.CompoundTag)) { + CompoundTag tankTag = tagRoot.getCompoundOrEmpty("Tank"); getTank().readFromNBT(tankTag); - if(tankTag.contains("Empty", 1)){ + if((tankTag.get("Empty") instanceof net.minecraft.nbt.ByteTag)){ // empty the tank if NBT says its empty (not default behavior of Tank.readFromNBT(...) ) getTank().setFluid(null); } @@ -158,7 +158,7 @@ public void onDataFieldUpdate() { private boolean isPlasticFluid(Fluid fluid) { if(fluid == null) return false; - ResourceLocation id = net.minecraftforge.registries.ForgeRegistries.FLUIDS.getKey(fluid); + Identifier id = net.minecraftforge.registries.ForgeRegistries.FLUIDS.getKey(fluid); return id != null && ElectricAdvantage.INSTANCE.PLASTIC_FLUID_MATERIALS.contains(id.toString()); } diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/SteamPoweredElectricGeneratorBlock.java b/src/main/java/zone/moddev/mc/baseelectric/machines/SteamPoweredElectricGeneratorBlock.java index 8a785105..b6fc3920 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/SteamPoweredElectricGeneratorBlock.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/SteamPoweredElectricGeneratorBlock.java @@ -5,6 +5,9 @@ import cyano.poweradvantage.api.PowerConnectorContext; public class SteamPoweredElectricGeneratorBlock extends ElectricGeneratorBlock{ + public SteamPoweredElectricGeneratorBlock() { + super(machineProperties(0.75F).setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("steam_powered_generator"))); + } public static final ConduitType STEAM_POWER = new ConduitType("steam"); diff --git a/src/main/java/zone/moddev/mc/baseelectric/machines/SteamPoweredElectricGeneratorTileEntity.java b/src/main/java/zone/moddev/mc/baseelectric/machines/SteamPoweredElectricGeneratorTileEntity.java index 2db2a9b1..49c9a9dd 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/machines/SteamPoweredElectricGeneratorTileEntity.java +++ b/src/main/java/zone/moddev/mc/baseelectric/machines/SteamPoweredElectricGeneratorTileEntity.java @@ -177,7 +177,7 @@ protected void saveTo(CompoundTag tagRoot) { @Override protected void loadFrom(CompoundTag tagRoot) { - steam = tagRoot.getFloat("steam"); + steam = tagRoot.getFloatOr("steam", 0F); } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/migration/ElectricLegacyMigrations.java b/src/main/java/zone/moddev/mc/baseelectric/migration/ElectricLegacyMigrations.java index 498aa163..5b7a4dc0 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/migration/ElectricLegacyMigrations.java +++ b/src/main/java/zone/moddev/mc/baseelectric/migration/ElectricLegacyMigrations.java @@ -4,7 +4,7 @@ import cyano.poweradvantage.api.simple.BlockSimplePowerMachine; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.core.Direction; import zone.moddev.mc.baseelectric.ElectricAdvantage; import zone.moddev.mc.baseelectric.machines.ElectricDrillBlock; @@ -92,7 +92,7 @@ static boolean legacyDrillActive(int metadata) { return (metadata & 0x8) != 0; } - private static ResourceLocation id(String path) { - return ResourceLocation.fromNamespaceAndPath(ElectricAdvantage.MODID, path); + private static Identifier id(String path) { + return Identifier.fromNamespaceAndPath(ElectricAdvantage.MODID, path); } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/recipe/RecipeConditions.java b/src/main/java/zone/moddev/mc/baseelectric/recipe/RecipeConditions.java index 93e92c93..6777d123 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/recipe/RecipeConditions.java +++ b/src/main/java/zone/moddev/mc/baseelectric/recipe/RecipeConditions.java @@ -6,7 +6,7 @@ import com.mojang.serialization.DataResult; import com.mojang.serialization.MapCodec; import net.minecraftforge.common.crafting.conditions.ICondition; -import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.eventbus.api.bus.BusGroup; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; import zone.moddev.mc.baseelectric.ElectricAdvantage; @@ -36,7 +36,7 @@ public final class RecipeConditions { private RecipeConditions() {} - public static void register(IEventBus bus) { + public static void register(BusGroup bus) { SERIALIZERS.register(bus); } diff --git a/src/main/java/zone/moddev/mc/baseelectric/util/LegacyNbt.java b/src/main/java/zone/moddev/mc/baseelectric/util/LegacyNbt.java new file mode 100644 index 00000000..42805849 --- /dev/null +++ b/src/main/java/zone/moddev/mc/baseelectric/util/LegacyNbt.java @@ -0,0 +1,11 @@ +package zone.moddev.mc.baseelectric.util; + +import com.mojang.serialization.MapCodec; +import net.minecraft.nbt.CompoundTag; + +/** Keeps released machine fields at the root of native value input/output. */ +public final class LegacyNbt { + public static final MapCodec ROOT = MapCodec.assumeMapUnsafe(CompoundTag.CODEC); + + private LegacyNbt() {} +} diff --git a/src/main/java/zone/moddev/mc/baseelectric/util/RegistryIds.java b/src/main/java/zone/moddev/mc/baseelectric/util/RegistryIds.java new file mode 100644 index 00000000..52043d1f --- /dev/null +++ b/src/main/java/zone/moddev/mc/baseelectric/util/RegistryIds.java @@ -0,0 +1,20 @@ +package zone.moddev.mc.baseelectric.util; + +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.Identifier; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; + +/** Native properties require their persistent registry key before construction. */ +public final class RegistryIds { + private RegistryIds() {} + + public static ResourceKey block(String path) { + return ResourceKey.create(Registries.BLOCK, Identifier.fromNamespaceAndPath("baseelectric", path)); + } + + public static ResourceKey item(String path) { + return ResourceKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath("baseelectric", path)); + } +} diff --git a/src/main/java/zone/moddev/mc/baseelectric/util/crafting/ItemMatcher.java b/src/main/java/zone/moddev/mc/baseelectric/util/crafting/ItemMatcher.java index 4211777f..feef8a92 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/util/crafting/ItemMatcher.java +++ b/src/main/java/zone/moddev/mc/baseelectric/util/crafting/ItemMatcher.java @@ -13,7 +13,7 @@ import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.tags.TagKey; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; /** Matches a crafting ingredient using flattened items or Forge item tags. */ public final class ItemMatcher { @@ -66,8 +66,8 @@ public Collection getValidItems() { return copy; } - private static ResourceLocation tagId(String name) { - if (name.indexOf(':') >= 0) return ResourceLocation.parse(name); + private static Identifier tagId(String name) { + if (name.indexOf(':') >= 0) return Identifier.parse(name); String[][] forms = { {"ingot", "ingots"}, {"nugget", "nuggets"}, {"dust", "dusts"}, {"ore", "ores"}, {"block", "storage_blocks"}, {"plate", "plates"}, @@ -76,10 +76,10 @@ private static ResourceLocation tagId(String name) { for (String[] form : forms) { if (name.startsWith(form[0]) && name.length() > form[0].length()) { String material = name.substring(form[0].length()).toLowerCase(java.util.Locale.ROOT); - return ResourceLocation.fromNamespaceAndPath("forge", form[1] + "/" + material); + return Identifier.fromNamespaceAndPath("forge", form[1] + "/" + material); } } - return ResourceLocation.fromNamespaceAndPath("forge", name.toLowerCase(java.util.Locale.ROOT)); + return Identifier.fromNamespaceAndPath("forge", name.toLowerCase(java.util.Locale.ROOT)); } @Override diff --git a/src/main/java/zone/moddev/mc/baseelectric/util/crafting/RecipeDeconstructor.java b/src/main/java/zone/moddev/mc/baseelectric/util/crafting/RecipeDeconstructor.java index f85e47ee..cfcb0a0a 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/util/crafting/RecipeDeconstructor.java +++ b/src/main/java/zone/moddev/mc/baseelectric/util/crafting/RecipeDeconstructor.java @@ -1,17 +1,22 @@ package zone.moddev.mc.baseelectric.util.crafting; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; +import com.google.gson.JsonElement; +import com.mojang.serialization.JsonOps; +import net.minecraft.core.HolderLookup; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.context.ContextMap; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.display.SlotDisplayContext; import net.minecraft.world.level.Level; /** Recursive crafting solver used by the Electric Fabricator. */ @@ -19,8 +24,8 @@ public final class RecipeDeconstructor { private static final RecipeDeconstructor INSTANCE = new RecipeDeconstructor(); public static int RECURSION_LIMIT = 5; - private final Map>> recipeCache = new HashMap<>(); - private int cachedRecipeCount = -1; + private final Map> recipeCache = new HashMap<>(); + private Collection> cachedRecipes; private RecipeDeconstructor() {} @@ -30,24 +35,56 @@ public static RecipeDeconstructor getInstance() { public void invalidateRecipeCache() { recipeCache.clear(); - cachedRecipeCount = -1; + cachedRecipes = null; } private void initializeRecipeCache(Level world) { - Collection> recipes = world.getRecipeManager().getRecipes(); - if (cachedRecipeCount == recipes.size() && !recipeCache.isEmpty()) return; + if (!(world instanceof ServerLevel server)) return; + Collection> recipes = server.recipeAccess().getRecipes(); + if (cachedRecipes == recipes) return; recipeCache.clear(); for (RecipeHolder holder : recipes) { Recipe recipe = holder.value(); - ItemStack output = recipe.getResultItem(world.registryAccess()); - if (output == null || output.isEmpty()) continue; - recipeCache.computeIfAbsent(new ItemRecord(output), ignored -> new ArrayList<>()).add(recipe); + for (RecipePlan plan : describe(recipe, world.registryAccess())) { + recipeCache.computeIfAbsent(new ItemRecord(plan.result()), ignored -> new ArrayList<>()).add(plan); + } + } + cachedRecipes = recipes; + } + + record RecipePlan(ItemStack result, List ingredients) {} + + static List describe(Recipe recipe, HolderLookup.Provider registries) { + List ingredients = new ArrayList<>(recipe.placementInfo().ingredients()); + ContextMap context = new ContextMap.Builder().withParameter(SlotDisplayContext.REGISTRIES, registries) + .create(SlotDisplayContext.CONTEXT); + List displayedResults = recipe.display().stream() + .flatMap(display -> display.result().resolveForStacks(context).stream()) + .filter(result -> !result.isEmpty()).toList(); + if (!ingredients.isEmpty() && !displayedResults.isEmpty()) { + return displayedResults.stream().map(result -> new RecipePlan(result.copy(), List.copyOf(ingredients))).toList(); + } + var ops = registries.createSerializationContext(JsonOps.INSTANCE); + var encoded = Recipe.CODEC.encodeStart(ops, recipe).getOrThrow().getAsJsonObject(); + // Special processing recipes, including Base Metals crushing, are not recipe-book placeable. + if (ingredients.isEmpty() && encoded.has("ingredient")) { + ingredients.add(Ingredient.CODEC.parse(ops, encoded.get("ingredient")).getOrThrow()); + } else if (ingredients.isEmpty() && encoded.has("ingredients")) { + for (JsonElement input : encoded.getAsJsonArray("ingredients")) { + ingredients.add(Ingredient.CODEC.parse(ops, input).getOrThrow()); + } + } + if (ingredients.isEmpty()) return List.of(); + if (encoded.has("result")) { + ItemStack result = ItemStack.CODEC.parse(ops, encoded.get("result")).getOrThrow(); + return result.isEmpty() ? List.of() : List.of(new RecipePlan(result, List.copyOf(ingredients))); } - cachedRecipeCount = recipes.size(); + return displayedResults.stream().map(result -> new RecipePlan(result.copy(), List.copyOf(ingredients))).toList(); } public SerializedInventory attemptToCraft(Level world, ItemStack target, SerializedInventory inventory, AtomicReference output) { + if (!(world instanceof ServerLevel)) return null; initializeRecipeCache(world); return attemptToCraft(world, target, inventory, output, 0); } @@ -55,20 +92,19 @@ public SerializedInventory attemptToCraft(Level world, ItemStack target, private SerializedInventory attemptToCraft(Level world, ItemStack target, SerializedInventory inventory, AtomicReference output, int depth) { if (depth > RECURSION_LIMIT || target == null || target.isEmpty()) return null; - List> recipes = recipeCache.get(new ItemRecord(target)); + List recipes = recipeCache.get(new ItemRecord(target)); if (recipes == null || recipes.isEmpty()) return null; - for (Recipe recipe : recipes) { + for (RecipePlan recipe : recipes) { SerializedInventory candidate = inventory.copy(); boolean failed = false; - for (Ingredient ingredient : recipe.getIngredients()) { - if (ingredient == null || ingredient == Ingredient.EMPTY) continue; - ItemStack[] matching = ingredient.getItems(); - if (matching == null || matching.length == 0) { + for (Ingredient ingredient : recipe.ingredients()) { + List matching = ingredient.items().map(holder -> new ItemStack(holder.value())).toList(); + if (matching.isEmpty()) { failed = true; break; } - ItemMatcher matcher = new ItemMatcher(Arrays.asList(matching)); + ItemMatcher matcher = new ItemMatcher(matching); if (candidate.decrement(matcher)) continue; boolean craftedIngredient = false; @@ -94,7 +130,7 @@ private SerializedInventory attemptToCraft(Level world, ItemStack target, } } if (!failed) { - output.set(recipe.getResultItem(world.registryAccess()).copy()); + output.set(recipe.result().copy()); return candidate; } } diff --git a/src/main/java/zone/moddev/mc/baseelectric/util/farming/VirtualCrop.java b/src/main/java/zone/moddev/mc/baseelectric/util/farming/VirtualCrop.java index 6dd6088b..aabea912 100644 --- a/src/main/java/zone/moddev/mc/baseelectric/util/farming/VirtualCrop.java +++ b/src/main/java/zone/moddev/mc/baseelectric/util/farming/VirtualCrop.java @@ -84,12 +84,12 @@ public static VirtualCrop createVirtualCrop(ItemStack stack, Level w, BlockPos p private static Block resolveStemFruit(StemBlock stem, Level world) { - // Forge 52 exposes the registered fruit key through the native stem codec. + // Forge 61 exposes the registered fruit key through the native stem codec. var ops = world.registryAccess().createSerializationContext(JsonOps.INSTANCE); return StemBlock.CODEC.codec().encodeStart(ops, stem).result() .flatMap(data -> ResourceKey.codec(Registries.BLOCK) .parse(ops, data.getAsJsonObject().get("fruit")).result()) - .map(key -> world.registryAccess().registryOrThrow(Registries.BLOCK).get(key)) + .map(key -> world.registryAccess().lookupOrThrow(Registries.BLOCK).getValueOrThrow(key)) .orElse(null); } diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 5816058b..427e2221 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -2,6 +2,7 @@ modLoader="javafml" loaderVersion="${loader_version_range}" issueTrackerURL="https://github.com/MinecraftModDevelopmentMods/baseElectric/issues" license="GPL-3.0-only" +showAsResourcePack=false [[mods]] modId="baseelectric" @@ -30,13 +31,13 @@ side="BOTH" [[dependencies.baseelectric]] modId="basepower" mandatory=true -versionRange="[2.4.14.121011,3.0.0)" +versionRange="[2.4.15.121111,3.0.0)" ordering="AFTER" side="BOTH" [[dependencies.baseelectric]] modId="basemetals" -mandatory=false -versionRange="[3.1.2.121011,4.0.0)" +mandatory=true +versionRange="[3.1.2.121111,4.0.0)" ordering="AFTER" side="BOTH" diff --git a/src/main/resources/assets/baseelectric/items/alkaline_battery.json b/src/main/resources/assets/baseelectric/items/alkaline_battery.json new file mode 100644 index 00000000..ece4de30 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/alkaline_battery.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/alkaline_battery" + } +} diff --git a/src/main/resources/assets/baseelectric/items/battery_base.json b/src/main/resources/assets/baseelectric/items/battery_base.json new file mode 100644 index 00000000..01738b1e --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/battery_base.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/battery_base" + } +} diff --git a/src/main/resources/assets/baseelectric/items/blank_circuit_board.json b/src/main/resources/assets/baseelectric/items/blank_circuit_board.json new file mode 100644 index 00000000..b2a934bd --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/blank_circuit_board.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/blank_circuit_board" + } +} diff --git a/src/main/resources/assets/baseelectric/items/control_circuit.json b/src/main/resources/assets/baseelectric/items/control_circuit.json new file mode 100644 index 00000000..4aac8476 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/control_circuit.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/control_circuit" + } +} diff --git a/src/main/resources/assets/baseelectric/items/electric_battery_array.json b/src/main/resources/assets/baseelectric/items/electric_battery_array.json new file mode 100644 index 00000000..c38db7db --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/electric_battery_array.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/electric_battery_array" + } +} diff --git a/src/main/resources/assets/baseelectric/items/electric_conduit.json b/src/main/resources/assets/baseelectric/items/electric_conduit.json new file mode 100644 index 00000000..73594a76 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/electric_conduit.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/electric_conduit" + } +} diff --git a/src/main/resources/assets/baseelectric/items/electric_crusher.json b/src/main/resources/assets/baseelectric/items/electric_crusher.json new file mode 100644 index 00000000..2b2f40ae --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/electric_crusher.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/electric_crusher" + } +} diff --git a/src/main/resources/assets/baseelectric/items/electric_drill.json b/src/main/resources/assets/baseelectric/items/electric_drill.json new file mode 100644 index 00000000..81e2a37c --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/electric_drill.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/electric_drill" + } +} diff --git a/src/main/resources/assets/baseelectric/items/electric_fabricator.json b/src/main/resources/assets/baseelectric/items/electric_fabricator.json new file mode 100644 index 00000000..8884f476 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/electric_fabricator.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/electric_fabricator" + } +} diff --git a/src/main/resources/assets/baseelectric/items/electric_furnace.json b/src/main/resources/assets/baseelectric/items/electric_furnace.json new file mode 100644 index 00000000..18cad204 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/electric_furnace.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/electric_furnace" + } +} diff --git a/src/main/resources/assets/baseelectric/items/electric_oven.json b/src/main/resources/assets/baseelectric/items/electric_oven.json new file mode 100644 index 00000000..c9861e02 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/electric_oven.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/electric_oven" + } +} diff --git a/src/main/resources/assets/baseelectric/items/electric_pcb_printer.json b/src/main/resources/assets/baseelectric/items/electric_pcb_printer.json new file mode 100644 index 00000000..821c99ac --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/electric_pcb_printer.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/electric_pcb_printer" + } +} diff --git a/src/main/resources/assets/baseelectric/items/electric_pump.json b/src/main/resources/assets/baseelectric/items/electric_pump.json new file mode 100644 index 00000000..33b98a86 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/electric_pump.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/electric_pump" + } +} diff --git a/src/main/resources/assets/baseelectric/items/electric_still.json b/src/main/resources/assets/baseelectric/items/electric_still.json new file mode 100644 index 00000000..3bc09d2e --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/electric_still.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/electric_still" + } +} diff --git a/src/main/resources/assets/baseelectric/items/electric_switch.json b/src/main/resources/assets/baseelectric/items/electric_switch.json new file mode 100644 index 00000000..14131799 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/electric_switch.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/electric_switch" + } +} diff --git a/src/main/resources/assets/baseelectric/items/electric_track.json b/src/main/resources/assets/baseelectric/items/electric_track.json new file mode 100644 index 00000000..2c610e5c --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/electric_track.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/electric_track" + } +} diff --git a/src/main/resources/assets/baseelectric/items/generic_item.json b/src/main/resources/assets/baseelectric/items/generic_item.json new file mode 100644 index 00000000..3aac583a --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/generic_item.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/generic_item" + } +} diff --git a/src/main/resources/assets/baseelectric/items/geothermal_generator.json b/src/main/resources/assets/baseelectric/items/geothermal_generator.json new file mode 100644 index 00000000..1faac231 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/geothermal_generator.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/geothermal_generator" + } +} diff --git a/src/main/resources/assets/baseelectric/items/growth_chamber.json b/src/main/resources/assets/baseelectric/items/growth_chamber.json new file mode 100644 index 00000000..95351d84 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/growth_chamber.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/growth_chamber" + } +} diff --git a/src/main/resources/assets/baseelectric/items/growth_chamber_controller.json b/src/main/resources/assets/baseelectric/items/growth_chamber_controller.json new file mode 100644 index 00000000..85e10b62 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/growth_chamber_controller.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/growth_chamber_controller" + } +} diff --git a/src/main/resources/assets/baseelectric/items/hydroelectric_generator.json b/src/main/resources/assets/baseelectric/items/hydroelectric_generator.json new file mode 100644 index 00000000..1bfa3e5f --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/hydroelectric_generator.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/hydroelectric_generator" + } +} diff --git a/src/main/resources/assets/baseelectric/items/integrated_circuit.json b/src/main/resources/assets/baseelectric/items/integrated_circuit.json new file mode 100644 index 00000000..3dacc5d1 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/integrated_circuit.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/integrated_circuit" + } +} diff --git a/src/main/resources/assets/baseelectric/items/laser_turret.json b/src/main/resources/assets/baseelectric/items/laser_turret.json new file mode 100644 index 00000000..d4757d0a --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/laser_turret.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/laser_turret" + } +} diff --git a/src/main/resources/assets/baseelectric/items/laser_turret_evil.json b/src/main/resources/assets/baseelectric/items/laser_turret_evil.json new file mode 100644 index 00000000..869b7c62 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/laser_turret_evil.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/laser_turret_evil" + } +} diff --git a/src/main/resources/assets/baseelectric/items/lead_acid_battery.json b/src/main/resources/assets/baseelectric/items/lead_acid_battery.json new file mode 100644 index 00000000..c9310268 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/lead_acid_battery.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/lead_acid_battery" + } +} diff --git a/src/main/resources/assets/baseelectric/items/led_bar.json b/src/main/resources/assets/baseelectric/items/led_bar.json new file mode 100644 index 00000000..3ecc1358 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/led_bar.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/led_bar" + } +} diff --git a/src/main/resources/assets/baseelectric/items/li_ingot.json b/src/main/resources/assets/baseelectric/items/li_ingot.json new file mode 100644 index 00000000..b8c5f243 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/li_ingot.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/li_ingot" + } +} diff --git a/src/main/resources/assets/baseelectric/items/li_nugget.json b/src/main/resources/assets/baseelectric/items/li_nugget.json new file mode 100644 index 00000000..788c2b8c --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/li_nugget.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/li_nugget" + } +} diff --git a/src/main/resources/assets/baseelectric/items/li_ore.json b/src/main/resources/assets/baseelectric/items/li_ore.json new file mode 100644 index 00000000..22c40798 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/li_ore.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/li_ore" + } +} diff --git a/src/main/resources/assets/baseelectric/items/li_powder.json b/src/main/resources/assets/baseelectric/items/li_powder.json new file mode 100644 index 00000000..38e1ab9f --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/li_powder.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/li_powder" + } +} diff --git a/src/main/resources/assets/baseelectric/items/lithium_battery.json b/src/main/resources/assets/baseelectric/items/lithium_battery.json new file mode 100644 index 00000000..4b446b88 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/lithium_battery.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/lithium_battery" + } +} diff --git a/src/main/resources/assets/baseelectric/items/nickel_hydride_battery.json b/src/main/resources/assets/baseelectric/items/nickel_hydride_battery.json new file mode 100644 index 00000000..aba34078 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/nickel_hydride_battery.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/nickel_hydride_battery" + } +} diff --git a/src/main/resources/assets/baseelectric/items/petrolplastic_ingot.json b/src/main/resources/assets/baseelectric/items/petrolplastic_ingot.json new file mode 100644 index 00000000..5a729177 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/petrolplastic_ingot.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/petrolplastic_ingot" + } +} diff --git a/src/main/resources/assets/baseelectric/items/photovoltaic_generator.json b/src/main/resources/assets/baseelectric/items/photovoltaic_generator.json new file mode 100644 index 00000000..91ac8748 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/photovoltaic_generator.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/photovoltaic_generator" + } +} diff --git a/src/main/resources/assets/baseelectric/items/plastic_refinery.json b/src/main/resources/assets/baseelectric/items/plastic_refinery.json new file mode 100644 index 00000000..48d2dbab --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/plastic_refinery.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/plastic_refinery" + } +} diff --git a/src/main/resources/assets/baseelectric/items/psu.json b/src/main/resources/assets/baseelectric/items/psu.json new file mode 100644 index 00000000..2ea7ff92 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/psu.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/psu" + } +} diff --git a/src/main/resources/assets/baseelectric/items/pump_pipe_electric.json b/src/main/resources/assets/baseelectric/items/pump_pipe_electric.json new file mode 100644 index 00000000..1fed300e --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/pump_pipe_electric.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/pump_pipe_electric" + } +} diff --git a/src/main/resources/assets/baseelectric/items/silicon_ingot.json b/src/main/resources/assets/baseelectric/items/silicon_ingot.json new file mode 100644 index 00000000..dba37746 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/silicon_ingot.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/silicon_ingot" + } +} diff --git a/src/main/resources/assets/baseelectric/items/silicon_mix.json b/src/main/resources/assets/baseelectric/items/silicon_mix.json new file mode 100644 index 00000000..8ebfe0aa --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/silicon_mix.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/silicon_mix" + } +} diff --git a/src/main/resources/assets/baseelectric/items/solder.json b/src/main/resources/assets/baseelectric/items/solder.json new file mode 100644 index 00000000..c169f0cd --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/solder.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/solder" + } +} diff --git a/src/main/resources/assets/baseelectric/items/solder_mix.json b/src/main/resources/assets/baseelectric/items/solder_mix.json new file mode 100644 index 00000000..49e598ac --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/solder_mix.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/solder_mix" + } +} diff --git a/src/main/resources/assets/baseelectric/items/steam_powered_generator.json b/src/main/resources/assets/baseelectric/items/steam_powered_generator.json new file mode 100644 index 00000000..02dd5d39 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/steam_powered_generator.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/steam_powered_generator" + } +} diff --git a/src/main/resources/assets/baseelectric/items/sulfur_ore.json b/src/main/resources/assets/baseelectric/items/sulfur_ore.json new file mode 100644 index 00000000..dc0a7bd0 --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/sulfur_ore.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/sulfur_ore" + } +} diff --git a/src/main/resources/assets/baseelectric/items/sulfur_powder.json b/src/main/resources/assets/baseelectric/items/sulfur_powder.json new file mode 100644 index 00000000..0a28642e --- /dev/null +++ b/src/main/resources/assets/baseelectric/items/sulfur_powder.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "baseelectric:item/sulfur_powder" + } +} diff --git a/src/main/resources/data/baseelectric/recipe/alkaline_battery.json b/src/main/resources/data/baseelectric/recipe/alkaline_battery.json index 045ddc9b..baafb359 100644 --- a/src/main/resources/data/baseelectric/recipe/alkaline_battery.json +++ b/src/main/resources/data/baseelectric/recipe/alkaline_battery.json @@ -6,18 +6,10 @@ "pZp" ], "key": { - "X": { - "tag": "forge:ingots/iron" - }, - "Y": { - "item": "minecraft:gunpowder" - }, - "Z": { - "tag": "forge:ingots/zinc" - }, - "p": { - "tag": "forge:plastic" - } + "X": "#forge:ingots/iron", + "Y": "minecraft:gunpowder", + "Z": "#forge:ingots/zinc", + "p": "#forge:plastic" }, "result": { "id": "baseelectric:alkaline_battery" diff --git a/src/main/resources/data/baseelectric/recipe/blank_circuit_board_ingot_normal.json b/src/main/resources/data/baseelectric/recipe/blank_circuit_board_ingot_normal.json index 56c4bf15..49555418 100644 --- a/src/main/resources/data/baseelectric/recipe/blank_circuit_board_ingot_normal.json +++ b/src/main/resources/data/baseelectric/recipe/blank_circuit_board_ingot_normal.json @@ -1,12 +1,8 @@ { "type": "minecraft:crafting_shapeless", "ingredients": [ - { - "tag": "forge:plastic" - }, - { - "tag": "forge:ingots/copper" - } + "#forge:plastic", + "#forge:ingots/copper" ], "result": { "id": "baseelectric:blank_circuit_board", diff --git a/src/main/resources/data/baseelectric/recipe/blank_circuit_board_plate.json b/src/main/resources/data/baseelectric/recipe/blank_circuit_board_plate.json index e4c7c947..d4f2d666 100644 --- a/src/main/resources/data/baseelectric/recipe/blank_circuit_board_plate.json +++ b/src/main/resources/data/baseelectric/recipe/blank_circuit_board_plate.json @@ -1,12 +1,8 @@ { "type": "minecraft:crafting_shapeless", "ingredients": [ - { - "tag": "forge:plastic" - }, - { - "tag": "forge:plates/copper" - } + "#forge:plastic", + "#forge:plates/copper" ], "result": { "id": "baseelectric:blank_circuit_board", diff --git a/src/main/resources/data/baseelectric/recipe/control_circuit.json b/src/main/resources/data/baseelectric/recipe/control_circuit.json index f4cb8bba..44391bab 100644 --- a/src/main/resources/data/baseelectric/recipe/control_circuit.json +++ b/src/main/resources/data/baseelectric/recipe/control_circuit.json @@ -1,15 +1,9 @@ { "type": "minecraft:crafting_shapeless", "ingredients": [ - { - "item": "baseelectric:blank_circuit_board" - }, - { - "tag": "forge:microchips" - }, - { - "tag": "forge:solder" - } + "baseelectric:blank_circuit_board", + "#forge:microchips", + "#forge:solder" ], "result": { "id": "baseelectric:control_circuit" diff --git a/src/main/resources/data/baseelectric/recipe/crushing_control_circuit.json b/src/main/resources/data/baseelectric/recipe/crushing_control_circuit.json index 5d73a79d..8403fddf 100644 --- a/src/main/resources/data/baseelectric/recipe/crushing_control_circuit.json +++ b/src/main/resources/data/baseelectric/recipe/crushing_control_circuit.json @@ -1,8 +1,6 @@ { "type": "basemetals:crushing", - "ingredient": { - "item": "baseelectric:control_circuit" - }, + "ingredient": "baseelectric:control_circuit", "result": { "id": "baseelectric:integrated_circuit", "count": 1 diff --git a/src/main/resources/data/baseelectric/recipe/crushing_electric_furnace.json b/src/main/resources/data/baseelectric/recipe/crushing_electric_furnace.json index a83beb17..c9c2a920 100644 --- a/src/main/resources/data/baseelectric/recipe/crushing_electric_furnace.json +++ b/src/main/resources/data/baseelectric/recipe/crushing_electric_furnace.json @@ -1,8 +1,6 @@ { "type": "basemetals:crushing", - "ingredient": { - "item": "baseelectric:electric_furnace" - }, + "ingredient": "baseelectric:electric_furnace", "result": { "id": "baseelectric:psu", "count": 1 diff --git a/src/main/resources/data/baseelectric/recipe/crushing_lithium_ingot.json b/src/main/resources/data/baseelectric/recipe/crushing_lithium_ingot.json index 82ae9a6a..4c230032 100644 --- a/src/main/resources/data/baseelectric/recipe/crushing_lithium_ingot.json +++ b/src/main/resources/data/baseelectric/recipe/crushing_lithium_ingot.json @@ -1,8 +1,6 @@ { "type": "basemetals:crushing", - "ingredient": { - "tag": "forge:ingots/lithium" - }, + "ingredient": "#forge:ingots/lithium", "result": { "id": "baseelectric:li_powder", "count": 1 diff --git a/src/main/resources/data/baseelectric/recipe/crushing_lithium_ore.json b/src/main/resources/data/baseelectric/recipe/crushing_lithium_ore.json index 0dede269..9b0bb844 100644 --- a/src/main/resources/data/baseelectric/recipe/crushing_lithium_ore.json +++ b/src/main/resources/data/baseelectric/recipe/crushing_lithium_ore.json @@ -1,8 +1,6 @@ { "type": "basemetals:crushing", - "ingredient": { - "tag": "forge:ores/lithium" - }, + "ingredient": "#forge:ores/lithium", "result": { "id": "baseelectric:li_powder", "count": 2 diff --git a/src/main/resources/data/baseelectric/recipe/crushing_photovoltaic_generator.json b/src/main/resources/data/baseelectric/recipe/crushing_photovoltaic_generator.json index 202591ba..eb491ee4 100644 --- a/src/main/resources/data/baseelectric/recipe/crushing_photovoltaic_generator.json +++ b/src/main/resources/data/baseelectric/recipe/crushing_photovoltaic_generator.json @@ -1,8 +1,6 @@ { "type": "basemetals:crushing", - "ingredient": { - "item": "baseelectric:photovoltaic_generator" - }, + "ingredient": "baseelectric:photovoltaic_generator", "result": { "id": "baseelectric:psu", "count": 1 diff --git a/src/main/resources/data/baseelectric/recipe/crushing_psu.json b/src/main/resources/data/baseelectric/recipe/crushing_psu.json index d19f676d..cb3ffac5 100644 --- a/src/main/resources/data/baseelectric/recipe/crushing_psu.json +++ b/src/main/resources/data/baseelectric/recipe/crushing_psu.json @@ -1,8 +1,6 @@ { "type": "basemetals:crushing", - "ingredient": { - "item": "baseelectric:psu" - }, + "ingredient": "baseelectric:psu", "result": { "id": "baseelectric:control_circuit", "count": 1 diff --git a/src/main/resources/data/baseelectric/recipe/crushing_steam_powered_generator.json b/src/main/resources/data/baseelectric/recipe/crushing_steam_powered_generator.json index 83aacd7d..6cb258d4 100644 --- a/src/main/resources/data/baseelectric/recipe/crushing_steam_powered_generator.json +++ b/src/main/resources/data/baseelectric/recipe/crushing_steam_powered_generator.json @@ -1,8 +1,6 @@ { "type": "basemetals:crushing", - "ingredient": { - "item": "baseelectric:steam_powered_generator" - }, + "ingredient": "baseelectric:steam_powered_generator", "result": { "id": "baseelectric:psu", "count": 1 diff --git a/src/main/resources/data/baseelectric/recipe/crushing_sulfur_ore.json b/src/main/resources/data/baseelectric/recipe/crushing_sulfur_ore.json index 828f9ad0..693356f8 100644 --- a/src/main/resources/data/baseelectric/recipe/crushing_sulfur_ore.json +++ b/src/main/resources/data/baseelectric/recipe/crushing_sulfur_ore.json @@ -1,8 +1,6 @@ { "type": "basemetals:crushing", - "ingredient": { - "tag": "forge:ores/sulfur" - }, + "ingredient": "#forge:ores/sulfur", "result": { "id": "baseelectric:sulfur_powder", "count": 4 diff --git a/src/main/resources/data/baseelectric/recipe/electric_battery_array.json b/src/main/resources/data/baseelectric/recipe/electric_battery_array.json index 519c09ce..99975987 100644 --- a/src/main/resources/data/baseelectric/recipe/electric_battery_array.json +++ b/src/main/resources/data/baseelectric/recipe/electric_battery_array.json @@ -5,18 +5,10 @@ "pmp" ], "key": { - "X": { - "item": "minecraft:chest" - }, - "u": { - "tag": "forge:power_supply_units" - }, - "p": { - "tag": "forge:plates/steel" - }, - "m": { - "tag": "forge:frames/steel" - } + "X": "minecraft:chest", + "u": "#forge:power_supply_units", + "p": "#forge:plates/steel", + "m": "#forge:frames/steel" }, "result": { "id": "baseelectric:electric_battery_array" diff --git a/src/main/resources/data/baseelectric/recipe/electric_conduit_plastic_ingot.json b/src/main/resources/data/baseelectric/recipe/electric_conduit_plastic_ingot.json index 8663f3d2..5a8d1f9d 100644 --- a/src/main/resources/data/baseelectric/recipe/electric_conduit_plastic_ingot.json +++ b/src/main/resources/data/baseelectric/recipe/electric_conduit_plastic_ingot.json @@ -6,12 +6,8 @@ "xxx" ], "key": { - "x": { - "tag": "forge:plastic" - }, - "c": { - "tag": "forge:ingots/copper" - } + "x": "#forge:plastic", + "c": "#forge:ingots/copper" }, "result": { "id": "baseelectric:electric_conduit", diff --git a/src/main/resources/data/baseelectric/recipe/electric_conduit_plastic_rod.json b/src/main/resources/data/baseelectric/recipe/electric_conduit_plastic_rod.json index 3732f3b9..2b278d91 100644 --- a/src/main/resources/data/baseelectric/recipe/electric_conduit_plastic_rod.json +++ b/src/main/resources/data/baseelectric/recipe/electric_conduit_plastic_rod.json @@ -5,12 +5,8 @@ "cc" ], "key": { - "x": { - "tag": "forge:plastic" - }, - "c": { - "tag": "forge:rods/copper" - } + "x": "#forge:plastic", + "c": "#forge:rods/copper" }, "result": { "id": "baseelectric:electric_conduit" diff --git a/src/main/resources/data/baseelectric/recipe/electric_conduit_rubber_ingot.json b/src/main/resources/data/baseelectric/recipe/electric_conduit_rubber_ingot.json index 22c654fd..70423e8f 100644 --- a/src/main/resources/data/baseelectric/recipe/electric_conduit_rubber_ingot.json +++ b/src/main/resources/data/baseelectric/recipe/electric_conduit_rubber_ingot.json @@ -6,12 +6,8 @@ "xxx" ], "key": { - "x": { - "tag": "forge:rubber" - }, - "c": { - "tag": "forge:ingots/copper" - } + "x": "#forge:rubber", + "c": "#forge:ingots/copper" }, "result": { "id": "baseelectric:electric_conduit", diff --git a/src/main/resources/data/baseelectric/recipe/electric_conduit_rubber_rod.json b/src/main/resources/data/baseelectric/recipe/electric_conduit_rubber_rod.json index 82b10b38..90b7b9b9 100644 --- a/src/main/resources/data/baseelectric/recipe/electric_conduit_rubber_rod.json +++ b/src/main/resources/data/baseelectric/recipe/electric_conduit_rubber_rod.json @@ -5,12 +5,8 @@ "cc" ], "key": { - "x": { - "tag": "forge:rubber" - }, - "c": { - "tag": "forge:rods/copper" - } + "x": "#forge:rubber", + "c": "#forge:rods/copper" }, "result": { "id": "baseelectric:electric_conduit" diff --git a/src/main/resources/data/baseelectric/recipe/electric_crusher.json b/src/main/resources/data/baseelectric/recipe/electric_crusher.json index 6a9e78d2..eb2b27f7 100644 --- a/src/main/resources/data/baseelectric/recipe/electric_crusher.json +++ b/src/main/resources/data/baseelectric/recipe/electric_crusher.json @@ -5,21 +5,11 @@ "pmp" ], "key": { - "X": { - "tag": "forge:sprockets" - }, - "Y": { - "tag": "forge:gems/diamond" - }, - "u": { - "tag": "forge:power_supply_units" - }, - "p": { - "tag": "forge:plates/steel" - }, - "m": { - "tag": "forge:frames/steel" - } + "X": "#forge:sprockets", + "Y": "#forge:gems/diamond", + "u": "#forge:power_supply_units", + "p": "#forge:plates/steel", + "m": "#forge:frames/steel" }, "result": { "id": "baseelectric:electric_crusher" diff --git a/src/main/resources/data/baseelectric/recipe/electric_drill.json b/src/main/resources/data/baseelectric/recipe/electric_drill.json index 7a197306..92218660 100644 --- a/src/main/resources/data/baseelectric/recipe/electric_drill.json +++ b/src/main/resources/data/baseelectric/recipe/electric_drill.json @@ -5,18 +5,10 @@ "pmp" ], "key": { - "X": { - "tag": "forge:storage_blocks/diamond" - }, - "u": { - "tag": "forge:power_supply_units" - }, - "p": { - "tag": "forge:plates/steel" - }, - "m": { - "tag": "forge:frames/steel" - } + "X": "#forge:storage_blocks/diamond", + "u": "#forge:power_supply_units", + "p": "#forge:plates/steel", + "m": "#forge:frames/steel" }, "result": { "id": "baseelectric:electric_drill" diff --git a/src/main/resources/data/baseelectric/recipe/electric_fabricator.json b/src/main/resources/data/baseelectric/recipe/electric_fabricator.json index 93832ca7..b3a25c18 100644 --- a/src/main/resources/data/baseelectric/recipe/electric_fabricator.json +++ b/src/main/resources/data/baseelectric/recipe/electric_fabricator.json @@ -5,18 +5,10 @@ "pmp" ], "key": { - "X": { - "item": "minecraft:crafting_table" - }, - "u": { - "tag": "forge:power_supply_units" - }, - "p": { - "tag": "forge:plates/steel" - }, - "m": { - "tag": "forge:frames/steel" - } + "X": "minecraft:crafting_table", + "u": "#forge:power_supply_units", + "p": "#forge:plates/steel", + "m": "#forge:frames/steel" }, "result": { "id": "baseelectric:electric_fabricator" diff --git a/src/main/resources/data/baseelectric/recipe/electric_furnace.json b/src/main/resources/data/baseelectric/recipe/electric_furnace.json index b136920a..a0d00e33 100644 --- a/src/main/resources/data/baseelectric/recipe/electric_furnace.json +++ b/src/main/resources/data/baseelectric/recipe/electric_furnace.json @@ -6,12 +6,8 @@ "bbb" ], "key": { - "b": { - "item": "minecraft:bricks" - }, - "u": { - "tag": "forge:power_supply_units" - } + "b": "minecraft:bricks", + "u": "#forge:power_supply_units" }, "result": { "id": "baseelectric:electric_furnace" diff --git a/src/main/resources/data/baseelectric/recipe/electric_oven.json b/src/main/resources/data/baseelectric/recipe/electric_oven.json index 135e1ba4..59d98362 100644 --- a/src/main/resources/data/baseelectric/recipe/electric_oven.json +++ b/src/main/resources/data/baseelectric/recipe/electric_oven.json @@ -5,21 +5,11 @@ "pmp" ], "key": { - "X": { - "tag": "forge:glass_panes" - }, - "Y": { - "tag": "forge:power_supply_units" - }, - "u": { - "tag": "forge:power_supply_units" - }, - "p": { - "tag": "forge:plates/steel" - }, - "m": { - "tag": "forge:frames/steel" - } + "X": "#forge:glass_panes", + "Y": "#forge:power_supply_units", + "u": "#forge:power_supply_units", + "p": "#forge:plates/steel", + "m": "#forge:frames/steel" }, "result": { "id": "baseelectric:electric_oven" diff --git a/src/main/resources/data/baseelectric/recipe/electric_pump.json b/src/main/resources/data/baseelectric/recipe/electric_pump.json index 78c92615..d49e82d1 100644 --- a/src/main/resources/data/baseelectric/recipe/electric_pump.json +++ b/src/main/resources/data/baseelectric/recipe/electric_pump.json @@ -5,21 +5,11 @@ "pmp" ], "key": { - "X": { - "item": "minecraft:piston" - }, - "Y": { - "item": "minecraft:bucket" - }, - "u": { - "tag": "forge:power_supply_units" - }, - "p": { - "tag": "forge:plates/steel" - }, - "m": { - "tag": "forge:frames/steel" - } + "X": "minecraft:piston", + "Y": "minecraft:bucket", + "u": "#forge:power_supply_units", + "p": "#forge:plates/steel", + "m": "#forge:frames/steel" }, "result": { "id": "baseelectric:electric_pump" diff --git a/src/main/resources/data/baseelectric/recipe/electric_still.json b/src/main/resources/data/baseelectric/recipe/electric_still.json index 31a065d0..af14f17f 100644 --- a/src/main/resources/data/baseelectric/recipe/electric_still.json +++ b/src/main/resources/data/baseelectric/recipe/electric_still.json @@ -5,21 +5,11 @@ "pmp" ], "key": { - "X": { - "item": "minecraft:bucket" - }, - "Y": { - "item": "minecraft:bucket" - }, - "u": { - "tag": "forge:power_supply_units" - }, - "p": { - "tag": "forge:plates/steel" - }, - "m": { - "tag": "forge:frames/steel" - } + "X": "minecraft:bucket", + "Y": "minecraft:bucket", + "u": "#forge:power_supply_units", + "p": "#forge:plates/steel", + "m": "#forge:frames/steel" }, "result": { "id": "baseelectric:electric_still" diff --git a/src/main/resources/data/baseelectric/recipe/electric_switch.json b/src/main/resources/data/baseelectric/recipe/electric_switch.json index 94dfe6e7..17148edf 100644 --- a/src/main/resources/data/baseelectric/recipe/electric_switch.json +++ b/src/main/resources/data/baseelectric/recipe/electric_switch.json @@ -5,15 +5,9 @@ "pfp" ], "key": { - "L": { - "item": "minecraft:lever" - }, - "p": { - "tag": "forge:wires" - }, - "f": { - "tag": "forge:frames/steel" - } + "L": "minecraft:lever", + "p": "#forge:wires", + "f": "#forge:frames/steel" }, "result": { "id": "baseelectric:electric_switch" diff --git a/src/main/resources/data/baseelectric/recipe/electric_track.json b/src/main/resources/data/baseelectric/recipe/electric_track.json index 31fa7b29..35495362 100644 --- a/src/main/resources/data/baseelectric/recipe/electric_track.json +++ b/src/main/resources/data/baseelectric/recipe/electric_track.json @@ -1,12 +1,8 @@ { "type": "minecraft:crafting_shapeless", "ingredients": [ - { - "item": "baseelectric:electric_conduit" - }, - { - "item": "basepower:steel_frame" - } + "baseelectric:electric_conduit", + "basepower:steel_frame" ], "result": { "id": "baseelectric:electric_track" diff --git a/src/main/resources/data/baseelectric/recipe/growth_chamber.json b/src/main/resources/data/baseelectric/recipe/growth_chamber.json index a0857156..96d26649 100644 --- a/src/main/resources/data/baseelectric/recipe/growth_chamber.json +++ b/src/main/resources/data/baseelectric/recipe/growth_chamber.json @@ -5,21 +5,11 @@ "pmp" ], "key": { - "X": { - "item": "minecraft:flower_pot" - }, - "Y": { - "tag": "forge:microchips" - }, - "u": { - "tag": "forge:power_supply_units" - }, - "p": { - "tag": "forge:plates/steel" - }, - "m": { - "tag": "forge:frames/steel" - } + "X": "minecraft:flower_pot", + "Y": "#forge:microchips", + "u": "#forge:power_supply_units", + "p": "#forge:plates/steel", + "m": "#forge:frames/steel" }, "result": { "id": "baseelectric:growth_chamber" diff --git a/src/main/resources/data/baseelectric/recipe/growth_chamber_controller.json b/src/main/resources/data/baseelectric/recipe/growth_chamber_controller.json index 6278ea96..280704fc 100644 --- a/src/main/resources/data/baseelectric/recipe/growth_chamber_controller.json +++ b/src/main/resources/data/baseelectric/recipe/growth_chamber_controller.json @@ -5,21 +5,11 @@ "pmp" ], "key": { - "X": { - "item": "minecraft:flower_pot" - }, - "Y": { - "tag": "forge:circuit_boards" - }, - "u": { - "tag": "forge:power_supply_units" - }, - "p": { - "tag": "forge:plates/steel" - }, - "m": { - "tag": "forge:frames/steel" - } + "X": "minecraft:flower_pot", + "Y": "#forge:circuit_boards", + "u": "#forge:power_supply_units", + "p": "#forge:plates/steel", + "m": "#forge:frames/steel" }, "result": { "id": "baseelectric:growth_chamber_controller" diff --git a/src/main/resources/data/baseelectric/recipe/hydroelectric_generator.json b/src/main/resources/data/baseelectric/recipe/hydroelectric_generator.json index 6e32bc1a..04e806d1 100644 --- a/src/main/resources/data/baseelectric/recipe/hydroelectric_generator.json +++ b/src/main/resources/data/baseelectric/recipe/hydroelectric_generator.json @@ -5,21 +5,11 @@ "pmp" ], "key": { - "X": { - "tag": "forge:sprockets" - }, - "Y": { - "tag": "forge:sprockets" - }, - "u": { - "tag": "forge:power_supply_units" - }, - "p": { - "tag": "forge:plates/steel" - }, - "m": { - "tag": "forge:frames/steel" - } + "X": "#forge:sprockets", + "Y": "#forge:sprockets", + "u": "#forge:power_supply_units", + "p": "#forge:plates/steel", + "m": "#forge:frames/steel" }, "result": { "id": "baseelectric:hydroelectric_generator" diff --git a/src/main/resources/data/baseelectric/recipe/integrated_circuit_copper_normal.json b/src/main/resources/data/baseelectric/recipe/integrated_circuit_copper_normal.json index 22f00745..2dd3ea91 100644 --- a/src/main/resources/data/baseelectric/recipe/integrated_circuit_copper_normal.json +++ b/src/main/resources/data/baseelectric/recipe/integrated_circuit_copper_normal.json @@ -5,12 +5,8 @@ "ccc" ], "key": { - "s": { - "tag": "forge:ingots/silicon" - }, - "c": { - "tag": "forge:nuggets/copper" - } + "s": "#forge:ingots/silicon", + "c": "#forge:nuggets/copper" }, "result": { "id": "baseelectric:integrated_circuit", diff --git a/src/main/resources/data/baseelectric/recipe/integrated_circuit_copper_tech.json b/src/main/resources/data/baseelectric/recipe/integrated_circuit_copper_tech.json index 4839f933..993714b9 100644 --- a/src/main/resources/data/baseelectric/recipe/integrated_circuit_copper_tech.json +++ b/src/main/resources/data/baseelectric/recipe/integrated_circuit_copper_tech.json @@ -6,18 +6,10 @@ "ccc" ], "key": { - "p": { - "tag": "forge:plastic" - }, - "s": { - "tag": "forge:ingots/silicon" - }, - "r": { - "tag": "forge:dusts/redstone" - }, - "c": { - "tag": "forge:nuggets/copper" - } + "p": "#forge:plastic", + "s": "#forge:ingots/silicon", + "r": "#forge:dusts/redstone", + "c": "#forge:nuggets/copper" }, "result": { "id": "baseelectric:integrated_circuit", diff --git a/src/main/resources/data/baseelectric/recipe/integrated_circuit_gold_normal.json b/src/main/resources/data/baseelectric/recipe/integrated_circuit_gold_normal.json index dae0f3d5..c7af1369 100644 --- a/src/main/resources/data/baseelectric/recipe/integrated_circuit_gold_normal.json +++ b/src/main/resources/data/baseelectric/recipe/integrated_circuit_gold_normal.json @@ -5,12 +5,8 @@ "ccc" ], "key": { - "s": { - "tag": "forge:ingots/silicon" - }, - "c": { - "tag": "forge:nuggets/gold" - } + "s": "#forge:ingots/silicon", + "c": "#forge:nuggets/gold" }, "result": { "id": "baseelectric:integrated_circuit", diff --git a/src/main/resources/data/baseelectric/recipe/integrated_circuit_gold_tech.json b/src/main/resources/data/baseelectric/recipe/integrated_circuit_gold_tech.json index 28569878..928b14af 100644 --- a/src/main/resources/data/baseelectric/recipe/integrated_circuit_gold_tech.json +++ b/src/main/resources/data/baseelectric/recipe/integrated_circuit_gold_tech.json @@ -6,18 +6,10 @@ "ccc" ], "key": { - "p": { - "tag": "forge:plastic" - }, - "s": { - "tag": "forge:ingots/silicon" - }, - "r": { - "tag": "forge:dusts/redstone" - }, - "c": { - "tag": "forge:nuggets/gold" - } + "p": "#forge:plastic", + "s": "#forge:ingots/silicon", + "r": "#forge:dusts/redstone", + "c": "#forge:nuggets/gold" }, "result": { "id": "baseelectric:integrated_circuit", diff --git a/src/main/resources/data/baseelectric/recipe/integrated_circuit_tin_normal.json b/src/main/resources/data/baseelectric/recipe/integrated_circuit_tin_normal.json index f97f9f42..41f6de6e 100644 --- a/src/main/resources/data/baseelectric/recipe/integrated_circuit_tin_normal.json +++ b/src/main/resources/data/baseelectric/recipe/integrated_circuit_tin_normal.json @@ -5,12 +5,8 @@ "ccc" ], "key": { - "s": { - "tag": "forge:ingots/silicon" - }, - "c": { - "tag": "forge:nuggets/tin" - } + "s": "#forge:ingots/silicon", + "c": "#forge:nuggets/tin" }, "result": { "id": "baseelectric:integrated_circuit", diff --git a/src/main/resources/data/baseelectric/recipe/integrated_circuit_tin_tech.json b/src/main/resources/data/baseelectric/recipe/integrated_circuit_tin_tech.json index 1cb2cc18..64fb895c 100644 --- a/src/main/resources/data/baseelectric/recipe/integrated_circuit_tin_tech.json +++ b/src/main/resources/data/baseelectric/recipe/integrated_circuit_tin_tech.json @@ -6,18 +6,10 @@ "ccc" ], "key": { - "p": { - "tag": "forge:plastic" - }, - "s": { - "tag": "forge:ingots/silicon" - }, - "r": { - "tag": "forge:dusts/redstone" - }, - "c": { - "tag": "forge:nuggets/tin" - } + "p": "#forge:plastic", + "s": "#forge:ingots/silicon", + "r": "#forge:dusts/redstone", + "c": "#forge:nuggets/tin" }, "result": { "id": "baseelectric:integrated_circuit", diff --git a/src/main/resources/data/baseelectric/recipe/laser_turret_diamond_emerald.json b/src/main/resources/data/baseelectric/recipe/laser_turret_diamond_emerald.json index e54d2d09..5e49ed16 100644 --- a/src/main/resources/data/baseelectric/recipe/laser_turret_diamond_emerald.json +++ b/src/main/resources/data/baseelectric/recipe/laser_turret_diamond_emerald.json @@ -5,21 +5,11 @@ "pmp" ], "key": { - "X": { - "tag": "forge:gems/diamond" - }, - "Y": { - "tag": "forge:gems/emerald" - }, - "u": { - "tag": "forge:power_supply_units" - }, - "p": { - "tag": "forge:plates/steel" - }, - "m": { - "tag": "forge:frames/steel" - } + "X": "#forge:gems/diamond", + "Y": "#forge:gems/emerald", + "u": "#forge:power_supply_units", + "p": "#forge:plates/steel", + "m": "#forge:frames/steel" }, "result": { "id": "baseelectric:laser_turret" diff --git a/src/main/resources/data/baseelectric/recipe/laser_turret_emerald_diamond.json b/src/main/resources/data/baseelectric/recipe/laser_turret_emerald_diamond.json index 70a0c25e..efde808b 100644 --- a/src/main/resources/data/baseelectric/recipe/laser_turret_emerald_diamond.json +++ b/src/main/resources/data/baseelectric/recipe/laser_turret_emerald_diamond.json @@ -5,21 +5,11 @@ "pmp" ], "key": { - "X": { - "tag": "forge:gems/emerald" - }, - "Y": { - "tag": "forge:gems/diamond" - }, - "u": { - "tag": "forge:power_supply_units" - }, - "p": { - "tag": "forge:plates/steel" - }, - "m": { - "tag": "forge:frames/steel" - } + "X": "#forge:gems/emerald", + "Y": "#forge:gems/diamond", + "u": "#forge:power_supply_units", + "p": "#forge:plates/steel", + "m": "#forge:frames/steel" }, "result": { "id": "baseelectric:laser_turret" diff --git a/src/main/resources/data/baseelectric/recipe/lead_acid_battery_dust_sulfur.json b/src/main/resources/data/baseelectric/recipe/lead_acid_battery_dust_sulfur.json index a3fafc7e..bb6bafe1 100644 --- a/src/main/resources/data/baseelectric/recipe/lead_acid_battery_dust_sulfur.json +++ b/src/main/resources/data/baseelectric/recipe/lead_acid_battery_dust_sulfur.json @@ -6,18 +6,10 @@ "pZp" ], "key": { - "X": { - "tag": "forge:ingots/lead" - }, - "Y": { - "tag": "forge:dusts/sulfur" - }, - "Z": { - "item": "minecraft:water_bucket" - }, - "p": { - "tag": "forge:plastic" - } + "X": "#forge:ingots/lead", + "Y": "#forge:dusts/sulfur", + "Z": "minecraft:water_bucket", + "p": "#forge:plastic" }, "result": { "id": "baseelectric:lead_acid_battery" diff --git a/src/main/resources/data/baseelectric/recipe/lead_acid_battery_sulfur.json b/src/main/resources/data/baseelectric/recipe/lead_acid_battery_sulfur.json index d41f1fc2..7c5dd59a 100644 --- a/src/main/resources/data/baseelectric/recipe/lead_acid_battery_sulfur.json +++ b/src/main/resources/data/baseelectric/recipe/lead_acid_battery_sulfur.json @@ -6,18 +6,10 @@ "pZp" ], "key": { - "X": { - "tag": "forge:ingots/lead" - }, - "Y": { - "tag": "forge:sulfur" - }, - "Z": { - "item": "minecraft:water_bucket" - }, - "p": { - "tag": "forge:plastic" - } + "X": "#forge:ingots/lead", + "Y": "#forge:sulfur", + "Z": "minecraft:water_bucket", + "p": "#forge:plastic" }, "result": { "id": "baseelectric:lead_acid_battery" diff --git a/src/main/resources/data/baseelectric/recipe/led_bar.json b/src/main/resources/data/baseelectric/recipe/led_bar.json index 6efc898a..b4cfce99 100644 --- a/src/main/resources/data/baseelectric/recipe/led_bar.json +++ b/src/main/resources/data/baseelectric/recipe/led_bar.json @@ -6,15 +6,9 @@ "ccc" ], "key": { - "g": { - "tag": "forge:glass_panes" - }, - "x": { - "tag": "forge:microchips" - }, - "c": { - "tag": "forge:wires" - } + "g": "#forge:glass_panes", + "x": "#forge:microchips", + "c": "#forge:wires" }, "result": { "id": "baseelectric:led_bar", diff --git a/src/main/resources/data/baseelectric/recipe/lithium_battery.json b/src/main/resources/data/baseelectric/recipe/lithium_battery.json index d7577393..ae4cbc6b 100644 --- a/src/main/resources/data/baseelectric/recipe/lithium_battery.json +++ b/src/main/resources/data/baseelectric/recipe/lithium_battery.json @@ -6,18 +6,10 @@ "pZp" ], "key": { - "X": { - "tag": "forge:ingots/lithium" - }, - "Y": { - "tag": "forge:dusts/redstone" - }, - "Z": { - "tag": "forge:dusts/carbon" - }, - "p": { - "tag": "forge:plastic" - } + "X": "#forge:ingots/lithium", + "Y": "#forge:dusts/redstone", + "Z": "#forge:dusts/carbon", + "p": "#forge:plastic" }, "result": { "id": "baseelectric:lithium_battery" diff --git a/src/main/resources/data/baseelectric/recipe/lithium_ingot_from_nuggets.json b/src/main/resources/data/baseelectric/recipe/lithium_ingot_from_nuggets.json index 5148f81c..a9d1af1d 100644 --- a/src/main/resources/data/baseelectric/recipe/lithium_ingot_from_nuggets.json +++ b/src/main/resources/data/baseelectric/recipe/lithium_ingot_from_nuggets.json @@ -6,9 +6,7 @@ "xxx" ], "key": { - "x": { - "tag": "forge:nuggets/lithium" - } + "x": "#forge:nuggets/lithium" }, "result": { "id": "baseelectric:li_ingot" diff --git a/src/main/resources/data/baseelectric/recipe/lithium_ingot_from_ore.json b/src/main/resources/data/baseelectric/recipe/lithium_ingot_from_ore.json index 37885285..62084f34 100644 --- a/src/main/resources/data/baseelectric/recipe/lithium_ingot_from_ore.json +++ b/src/main/resources/data/baseelectric/recipe/lithium_ingot_from_ore.json @@ -1,8 +1,6 @@ { "type": "minecraft:smelting", - "ingredient": { - "item": "baseelectric:li_ore" - }, + "ingredient": "baseelectric:li_ore", "result": { "id": "baseelectric:li_ingot" }, diff --git a/src/main/resources/data/baseelectric/recipe/lithium_ingot_from_powder.json b/src/main/resources/data/baseelectric/recipe/lithium_ingot_from_powder.json index 4204fd57..81fe473e 100644 --- a/src/main/resources/data/baseelectric/recipe/lithium_ingot_from_powder.json +++ b/src/main/resources/data/baseelectric/recipe/lithium_ingot_from_powder.json @@ -1,8 +1,6 @@ { "type": "minecraft:smelting", - "ingredient": { - "item": "baseelectric:li_powder" - }, + "ingredient": "baseelectric:li_powder", "result": { "id": "baseelectric:li_ingot" }, diff --git a/src/main/resources/data/baseelectric/recipe/lithium_nuggets.json b/src/main/resources/data/baseelectric/recipe/lithium_nuggets.json index ac2d439e..3a8c54fe 100644 --- a/src/main/resources/data/baseelectric/recipe/lithium_nuggets.json +++ b/src/main/resources/data/baseelectric/recipe/lithium_nuggets.json @@ -1,9 +1,7 @@ { "type": "minecraft:crafting_shapeless", "ingredients": [ - { - "tag": "forge:ingots/lithium" - } + "#forge:ingots/lithium" ], "result": { "id": "baseelectric:li_nugget", diff --git a/src/main/resources/data/baseelectric/recipe/nickel_hydride_battery.json b/src/main/resources/data/baseelectric/recipe/nickel_hydride_battery.json index 682f758d..307128f3 100644 --- a/src/main/resources/data/baseelectric/recipe/nickel_hydride_battery.json +++ b/src/main/resources/data/baseelectric/recipe/nickel_hydride_battery.json @@ -6,18 +6,10 @@ "pZp" ], "key": { - "X": { - "tag": "forge:ingots/nickel" - }, - "Y": { - "tag": "forge:dusts/redstone" - }, - "Z": { - "item": "minecraft:water_bucket" - }, - "p": { - "tag": "forge:plastic" - } + "X": "#forge:ingots/nickel", + "Y": "#forge:dusts/redstone", + "Z": "minecraft:water_bucket", + "p": "#forge:plastic" }, "result": { "id": "baseelectric:nickel_hydride_battery" diff --git a/src/main/resources/data/baseelectric/recipe/photovoltaic_generator.json b/src/main/resources/data/baseelectric/recipe/photovoltaic_generator.json index e4c862bb..e8da3b41 100644 --- a/src/main/resources/data/baseelectric/recipe/photovoltaic_generator.json +++ b/src/main/resources/data/baseelectric/recipe/photovoltaic_generator.json @@ -6,18 +6,10 @@ "wuw" ], "key": { - "g": { - "tag": "forge:glass_panes" - }, - "s": { - "tag": "forge:ingots/silicon" - }, - "w": { - "tag": "forge:wires" - }, - "u": { - "tag": "forge:power_supply_units" - } + "g": "#forge:glass_panes", + "s": "#forge:ingots/silicon", + "w": "#forge:wires", + "u": "#forge:power_supply_units" }, "result": { "id": "baseelectric:photovoltaic_generator" diff --git a/src/main/resources/data/baseelectric/recipe/plastic_refinery.json b/src/main/resources/data/baseelectric/recipe/plastic_refinery.json index 1363ce25..df38fd1a 100644 --- a/src/main/resources/data/baseelectric/recipe/plastic_refinery.json +++ b/src/main/resources/data/baseelectric/recipe/plastic_refinery.json @@ -5,21 +5,11 @@ "pmp" ], "key": { - "X": { - "item": "minecraft:piston" - }, - "Y": { - "tag": "forge:sprockets" - }, - "u": { - "tag": "forge:power_supply_units" - }, - "p": { - "tag": "forge:plates/steel" - }, - "m": { - "tag": "forge:frames/steel" - } + "X": "minecraft:piston", + "Y": "#forge:sprockets", + "u": "#forge:power_supply_units", + "p": "#forge:plates/steel", + "m": "#forge:frames/steel" }, "result": { "id": "baseelectric:plastic_refinery" diff --git a/src/main/resources/data/baseelectric/recipe/power_supply_unit_iron_normal.json b/src/main/resources/data/baseelectric/recipe/power_supply_unit_iron_normal.json index 87f43c17..f5f54c9d 100644 --- a/src/main/resources/data/baseelectric/recipe/power_supply_unit_iron_normal.json +++ b/src/main/resources/data/baseelectric/recipe/power_supply_unit_iron_normal.json @@ -5,15 +5,9 @@ " s " ], "key": { - "w": { - "tag": "forge:wires" - }, - "c": { - "tag": "forge:circuit_boards" - }, - "s": { - "tag": "forge:ingots/iron" - } + "w": "#forge:wires", + "c": "#forge:circuit_boards", + "s": "#forge:ingots/iron" }, "result": { "id": "baseelectric:psu" diff --git a/src/main/resources/data/baseelectric/recipe/power_supply_unit_plate_steel_apocalyptic.json b/src/main/resources/data/baseelectric/recipe/power_supply_unit_plate_steel_apocalyptic.json index b89ae13b..976c4ba8 100644 --- a/src/main/resources/data/baseelectric/recipe/power_supply_unit_plate_steel_apocalyptic.json +++ b/src/main/resources/data/baseelectric/recipe/power_supply_unit_plate_steel_apocalyptic.json @@ -5,15 +5,9 @@ " s " ], "key": { - "w": { - "tag": "forge:wires" - }, - "c": { - "tag": "forge:circuit_boards" - }, - "s": { - "tag": "forge:plates/steel" - } + "w": "#forge:wires", + "c": "#forge:circuit_boards", + "s": "#forge:plates/steel" }, "result": { "id": "baseelectric:psu" diff --git a/src/main/resources/data/baseelectric/recipe/power_supply_unit_plate_steel_tech.json b/src/main/resources/data/baseelectric/recipe/power_supply_unit_plate_steel_tech.json index ce84c800..57f6e2a5 100644 --- a/src/main/resources/data/baseelectric/recipe/power_supply_unit_plate_steel_tech.json +++ b/src/main/resources/data/baseelectric/recipe/power_supply_unit_plate_steel_tech.json @@ -5,15 +5,9 @@ " s " ], "key": { - "w": { - "tag": "forge:wires" - }, - "c": { - "tag": "forge:circuit_boards" - }, - "s": { - "tag": "forge:plates/steel" - } + "w": "#forge:wires", + "c": "#forge:circuit_boards", + "s": "#forge:plates/steel" }, "result": { "id": "baseelectric:psu" diff --git a/src/main/resources/data/baseelectric/recipe/power_supply_unit_steel_normal.json b/src/main/resources/data/baseelectric/recipe/power_supply_unit_steel_normal.json index 453b4c37..8be41670 100644 --- a/src/main/resources/data/baseelectric/recipe/power_supply_unit_steel_normal.json +++ b/src/main/resources/data/baseelectric/recipe/power_supply_unit_steel_normal.json @@ -5,15 +5,9 @@ " s " ], "key": { - "w": { - "tag": "forge:wires" - }, - "c": { - "tag": "forge:circuit_boards" - }, - "s": { - "tag": "forge:ingots/steel" - } + "w": "#forge:wires", + "c": "#forge:circuit_boards", + "s": "#forge:ingots/steel" }, "result": { "id": "baseelectric:psu" diff --git a/src/main/resources/data/baseelectric/recipe/silicon_blend.json b/src/main/resources/data/baseelectric/recipe/silicon_blend.json index 5e34912b..39a922c7 100644 --- a/src/main/resources/data/baseelectric/recipe/silicon_blend.json +++ b/src/main/resources/data/baseelectric/recipe/silicon_blend.json @@ -1,12 +1,8 @@ { "type": "minecraft:crafting_shapeless", "ingredients": [ - { - "tag": "forge:sand" - }, - { - "tag": "forge:dusts/carbon" - } + "#forge:sand", + "#forge:dusts/carbon" ], "result": { "id": "baseelectric:silicon_mix" diff --git a/src/main/resources/data/baseelectric/recipe/silicon_ingot_from_blend.json b/src/main/resources/data/baseelectric/recipe/silicon_ingot_from_blend.json index 59c7c2de..d3ae9024 100644 --- a/src/main/resources/data/baseelectric/recipe/silicon_ingot_from_blend.json +++ b/src/main/resources/data/baseelectric/recipe/silicon_ingot_from_blend.json @@ -1,8 +1,6 @@ { "type": "minecraft:smelting", - "ingredient": { - "item": "baseelectric:silicon_mix" - }, + "ingredient": "baseelectric:silicon_mix", "result": { "id": "baseelectric:silicon_ingot" }, diff --git a/src/main/resources/data/baseelectric/recipe/solder_blend_tin_lead.json b/src/main/resources/data/baseelectric/recipe/solder_blend_tin_lead.json index ab6faff6..61eede5e 100644 --- a/src/main/resources/data/baseelectric/recipe/solder_blend_tin_lead.json +++ b/src/main/resources/data/baseelectric/recipe/solder_blend_tin_lead.json @@ -1,15 +1,9 @@ { "type": "minecraft:crafting_shapeless", "ingredients": [ - { - "tag": "forge:dusts/tin" - }, - { - "tag": "forge:dusts/tin" - }, - { - "tag": "forge:dusts/lead" - } + "#forge:dusts/tin", + "#forge:dusts/tin", + "#forge:dusts/lead" ], "result": { "id": "baseelectric:solder_mix", diff --git a/src/main/resources/data/baseelectric/recipe/solder_blend_tin_silver.json b/src/main/resources/data/baseelectric/recipe/solder_blend_tin_silver.json index 4c236933..8bbedf72 100644 --- a/src/main/resources/data/baseelectric/recipe/solder_blend_tin_silver.json +++ b/src/main/resources/data/baseelectric/recipe/solder_blend_tin_silver.json @@ -1,15 +1,9 @@ { "type": "minecraft:crafting_shapeless", "ingredients": [ - { - "tag": "forge:dusts/tin" - }, - { - "tag": "forge:dusts/tin" - }, - { - "tag": "forge:dusts/silver" - } + "#forge:dusts/tin", + "#forge:dusts/tin", + "#forge:dusts/silver" ], "result": { "id": "baseelectric:solder_mix", diff --git a/src/main/resources/data/baseelectric/recipe/solder_from_blend.json b/src/main/resources/data/baseelectric/recipe/solder_from_blend.json index 26aaa57a..86594693 100644 --- a/src/main/resources/data/baseelectric/recipe/solder_from_blend.json +++ b/src/main/resources/data/baseelectric/recipe/solder_from_blend.json @@ -1,8 +1,6 @@ { "type": "minecraft:smelting", - "ingredient": { - "item": "baseelectric:solder_mix" - }, + "ingredient": "baseelectric:solder_mix", "result": { "id": "baseelectric:solder" }, diff --git a/src/main/resources/data/baseelectric/recipe/steam_powered_generator.json b/src/main/resources/data/baseelectric/recipe/steam_powered_generator.json index 1dd68494..1f87f574 100644 --- a/src/main/resources/data/baseelectric/recipe/steam_powered_generator.json +++ b/src/main/resources/data/baseelectric/recipe/steam_powered_generator.json @@ -5,21 +5,11 @@ "pmp" ], "key": { - "X": { - "tag": "forge:conduits/steam" - }, - "Y": { - "tag": "forge:governors" - }, - "u": { - "tag": "forge:power_supply_units" - }, - "p": { - "tag": "forge:plates/steel" - }, - "m": { - "tag": "forge:frames/steel" - } + "X": "#forge:conduits/steam", + "Y": "#forge:governors", + "u": "#forge:power_supply_units", + "p": "#forge:plates/steel", + "m": "#forge:frames/steel" }, "result": { "id": "baseelectric:steam_powered_generator" diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index cabf58ff..e1986b3d 100644 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -1,7 +1,7 @@ { "pack":{ - "pack_format":34, - "supported_formats":{"min_inclusive":34,"max_inclusive":48}, + "min_format":[94,1], + "max_format":[94,1], "description":"baseElectric" } } diff --git a/src/test/java/zone/moddev/mc/baseelectric/blocks/NativeBlockContractTest.java b/src/test/java/zone/moddev/mc/baseelectric/blocks/NativeBlockContractTest.java index b3278713..62d5a5a0 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/blocks/NativeBlockContractTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/blocks/NativeBlockContractTest.java @@ -39,7 +39,7 @@ public class NativeBlockContractTest { assertFalse(state.isRedstoneConductor(net.minecraft.world.level.EmptyBlockGetter.INSTANCE, BlockPos.ZERO)); assertEquals(Shapes.block().bounds(), block.getCollisionShape(state, null, BlockPos.ZERO, CollisionContext.empty()).bounds()); - assertFalse(state.isSolidRender(net.minecraft.world.level.EmptyBlockGetter.INSTANCE, BlockPos.ZERO)); + assertFalse(state.isSolidRender()); assertTrue(state.isCollisionShapeFullBlock(net.minecraft.world.level.EmptyBlockGetter.INSTANCE, BlockPos.ZERO)); assertEquals(6, state.getProperties().size()); assertSame(BlockSimplePowerConduit.NORTH, ElectricScaffoldBlock.NORTH); @@ -57,16 +57,20 @@ public class NativeBlockContractTest { assertSame(BlockSimplePowerConduit.class, scaffold.getMethod("getStateForPlacement", BlockPlaceContext.class).getDeclaringClass()); assertSame(BlockSimplePowerConduit.class, - scaffold.getMethod("updateShape", BlockState.class, Direction.class, BlockState.class, - LevelAccessor.class, BlockPos.class, BlockPos.class).getDeclaringClass()); + scaffold.getMethod("updateShape", BlockState.class, net.minecraft.world.level.LevelReader.class, + net.minecraft.world.level.ScheduledTickAccess.class, BlockPos.class, Direction.class, + BlockPos.class, BlockState.class, net.minecraft.util.RandomSource.class).getDeclaringClass()); assertSame(BlockSimplePowerConduit.class, scaffold.getMethod("canAcceptConnection", PowerConnectorContext.class).getDeclaringClass()); assertSame(ConduitBlock.class, scaffold.getMethod("onPlace", BlockState.class, Level.class, BlockPos.class, BlockState.class, boolean.class).getDeclaringClass()); assertSame(ConduitBlock.class, - scaffold.getMethod("onRemove", BlockState.class, Level.class, BlockPos.class, - BlockState.class, boolean.class).getDeclaringClass()); + inheritedMethod(scaffold, "affectNeighborsAfterRemoval", BlockState.class, + net.minecraft.server.level.ServerLevel.class, BlockPos.class, boolean.class).getDeclaringClass()); + assertSame(ConduitBlock.class, + scaffold.getMethod("wasExploded", net.minecraft.server.level.ServerLevel.class, + BlockPos.class, Explosion.class).getDeclaringClass()); assertSame(ConduitBlock.class, scaffold.getMethod("wasExploded", Level.class, BlockPos.class, Explosion.class).getDeclaringClass()); ElectricScaffoldBlock block = new ElectricScaffoldBlock(); @@ -76,6 +80,15 @@ public class NativeBlockContractTest { assertFalse(block.isPowerSource(Power.ELECTRIC_POWER)); } + private static java.lang.reflect.Method inheritedMethod(Class type, String name, Class... parameters) + throws NoSuchMethodException { + for (Class current = type; current != null; current = current.getSuperclass()) { + try { return current.getDeclaredMethod(name, parameters); } + catch (NoSuchMethodException absent) { /* Continue through protected native callbacks. */ } + } + throw new NoSuchMethodException(type.getName() + "." + name); + } + @Test public void customMachinePropertiesKeepDrillAndBothTurretsNonSolid() { assertFalse(new ElectricDrillBlock().defaultBlockState().canOcclude()); assertFalse(new LaserTurretBlock(false).defaultBlockState().canOcclude()); @@ -111,6 +124,6 @@ public class NativeBlockContractTest { @Test public void hiddenPumpPipeUsesNativeNoLootTable() { BlockState state = new PumpPipeBlock().defaultBlockState(); - assertTrue(state.getDrops(new LootParams.Builder(null)).isEmpty()); + assertTrue(state.getDrops(new LootParams.Builder((net.minecraft.server.level.ServerLevel) null)).isEmpty()); } } diff --git a/src/test/java/zone/moddev/mc/baseelectric/blocks/OreHarvestContractTest.java b/src/test/java/zone/moddev/mc/baseelectric/blocks/OreHarvestContractTest.java index 30c5f1dc..236b8ea7 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/blocks/OreHarvestContractTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/blocks/OreHarvestContractTest.java @@ -60,8 +60,8 @@ private static void bindHarvestTags(Block block, String id) throws Exception { } // Vanilla's wooden and golden incorrect-tool tags both include needs_stone_tool. if (tags.contains(BlockTags.NEEDS_STONE_TOOL)) { - tags.add(net.minecraft.world.item.Tiers.WOOD.getIncorrectBlocksForDrops()); - tags.add(net.minecraft.world.item.Tiers.GOLD.getIncorrectBlocksForDrops()); + tags.add(net.minecraft.world.item.ToolMaterial.WOOD.incorrectBlocksForDrops()); + tags.add(net.minecraft.world.item.ToolMaterial.GOLD.incorrectBlocksForDrops()); } // Bind only the fresh test block's holder; leave the global registry alone. block.builtInRegistryHolder().bindTags(tags); @@ -80,12 +80,13 @@ private static boolean canHarvest(BlockState state, ItemStack held) throws Excep // Only omit world construction. Harvest eligibility still executes Forge's native hook. private static final class HarvestPlayer extends Player { private ItemStack held; - private HarvestPlayer() { super(null, BlockPos.ZERO, 0, (GameProfile) null); } + private HarvestPlayer() { super(null, (GameProfile) null); } @Override public ItemStack getMainHandItem() { return held; } @Override public boolean hasCorrectToolForDrops(BlockState state) { return !state.requiresCorrectToolForDrops() || held.isCorrectToolForDrops(state); } @Override public boolean isSpectator() { return false; } @Override public boolean isCreative() { return false; } + @Override public net.minecraft.world.level.GameType gameMode() { return net.minecraft.world.level.GameType.SURVIVAL; } } } diff --git a/src/test/java/zone/moddev/mc/baseelectric/entities/ElectricOperationalHydroturbineAnchorTest.java b/src/test/java/zone/moddev/mc/baseelectric/entities/ElectricOperationalHydroturbineAnchorTest.java index 3fe9e97f..da1adedc 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/entities/ElectricOperationalHydroturbineAnchorTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/entities/ElectricOperationalHydroturbineAnchorTest.java @@ -27,9 +27,9 @@ public class ElectricOperationalHydroturbineAnchorTest { @Test public void nativeEntityLoadStillClampsOverspeedMotionAndPreservesItsBoundary() throws Exception { ControlEntity control = new ControlEntity(controlType(), world()); - CompoundTag tag = control.saveWithoutId(new CompoundTag()); + CompoundTag tag = save(control); tag.put("Motion", motion(16.226, -10.001, 10)); - control.load(tag); + control.load(NativeTestBootstrap.input(tag)); assertEquals(new Vec3(0, 0, 10), control.getDeltaMovement()); assertTrue(control.isPushedByFluid()); } @@ -43,9 +43,9 @@ public class ElectricOperationalHydroturbineAnchorTest { @Test public void legacyMotionInsideTheNativeLimitIsNotArbitrarilyCleared() throws Exception { HydroturbineEntity turbine = new HydroturbineEntity(turbineType(), world()); - CompoundTag saved = turbine.saveWithoutId(new CompoundTag()); + CompoundTag saved = save(turbine); saved.put("Motion", motion(5.5, -2, 0)); - turbine.load(saved); + turbine.load(NativeTestBootstrap.input(saved)); assertEquals(new Vec3(5.5, -2, 0), turbine.getDeltaMovement()); assertFalse(turbine.isPushedByFluid()); } @@ -55,22 +55,30 @@ public class ElectricOperationalHydroturbineAnchorTest { Level world = world(); HydroturbineEntity original = new HydroturbineEntity(type, world); original.setPos(56856.5, 81, 50008.5); - CompoundTag saved = original.saveWithoutId(new CompoundTag()); + CompoundTag saved = save(original); int[] parent = {56856, 82, 50008}; saved.putIntArray("parentPos", parent); for (int pass = 0; pass < 3; pass++) { HydroturbineEntity loaded = new HydroturbineEntity(type, world); - loaded.load(saved); - CompoundTag next = loaded.saveWithoutId(new CompoundTag()); - assertEquals(saved.getUUID("UUID"), next.getUUID("UUID")); - assertEquals(saved.getList("Pos", 6), next.getList("Pos", 6)); - assertEquals(motion(0, 0, 0), next.getList("Motion", 6)); - assertArrayEquals(parent, next.getIntArray("parentPos")); + loaded.load(NativeTestBootstrap.input(saved)); + CompoundTag next = save(loaded); + assertEquals(saved.read("UUID", net.minecraft.core.UUIDUtil.CODEC).orElseThrow(), + next.read("UUID", net.minecraft.core.UUIDUtil.CODEC).orElseThrow()); + assertEquals(saved.getList("Pos").filter(list -> list.stream().allMatch(entry -> entry.getId() == 6)).orElseGet(net.minecraft.nbt.ListTag::new), next.getList("Pos").filter(list -> list.stream().allMatch(entry -> entry.getId() == 6)).orElseGet(net.minecraft.nbt.ListTag::new)); + assertEquals(motion(0, 0, 0), next.getList("Motion").filter(list -> list.stream().allMatch(entry -> entry.getId() == 6)).orElseGet(net.minecraft.nbt.ListTag::new)); + assertArrayEquals(parent, next.getIntArray("parentPos").orElseThrow()); assertFalse(loaded.isPushedByFluid()); saved = next; } } + private static CompoundTag save(Entity entity) { + var output = net.minecraft.world.level.storage.TagValueOutput.createWithContext( + net.minecraft.util.ProblemReporter.DISCARDING, NativeTestBootstrap.registries()); + entity.saveWithoutId(output); + return output.buildResult(); + } + private static ListTag motion(double x, double y, double z) { ListTag list = new ListTag(); list.add(DoubleTag.valueOf(x)); list.add(DoubleTag.valueOf(y)); list.add(DoubleTag.valueOf(z)); @@ -79,12 +87,14 @@ private static ListTag motion(double x, double y, double z) { private static EntityType turbineType() { return EntityType.Builder.of(HydroturbineEntity::new, MobCategory.MISC) - .sized(1, 1).build("baseelectric:test_anchored_turbine"); + .sized(1, 1).build(net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.ENTITY_TYPE, + net.minecraft.resources.Identifier.parse("baseelectric:test_anchored_turbine"))); } private static EntityType controlType() { return EntityType.Builder.of(ControlEntity::new, MobCategory.MISC) - .sized(1, 1).build("baseelectric:test_native_motion_control"); + .sized(1, 1).build(net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.ENTITY_TYPE, + net.minecraft.resources.Identifier.parse("baseelectric:test_native_motion_control"))); } private static Level world() throws Exception { @@ -101,15 +111,16 @@ private static Level world() throws Exception { private static final class NoTickWorld extends ServerLevel { private NoTickWorld() { - super(null, null, null, null, null, null, null, false, 0L, Collections.emptyList(), false, null); + super(null, null, null, null, null, null, false, 0L, Collections.emptyList(), false, null); } } private static final class ControlEntity extends Entity { ControlEntity(EntityType type, Level world) { super(type, world); } @Override protected void defineSynchedData(net.minecraft.network.syncher.SynchedEntityData.Builder builder) {} - @Override protected void readAdditionalSaveData(CompoundTag tag) {} - @Override protected void addAdditionalSaveData(CompoundTag tag) {} + @Override protected void readAdditionalSaveData(net.minecraft.world.level.storage.ValueInput tag) {} + @Override protected void addAdditionalSaveData(net.minecraft.world.level.storage.ValueOutput tag) {} + @Override public boolean hurtServer(ServerLevel level, net.minecraft.world.damagesource.DamageSource source, float amount) { return false; } @Override public Packet getAddEntityPacket(net.minecraft.server.level.ServerEntity tracker) { return null; } } } diff --git a/src/test/java/zone/moddev/mc/baseelectric/entities/HydroturbinePersistenceTest.java b/src/test/java/zone/moddev/mc/baseelectric/entities/HydroturbinePersistenceTest.java index c763e7f3..abdebfc6 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/entities/HydroturbinePersistenceTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/entities/HydroturbinePersistenceTest.java @@ -36,7 +36,7 @@ public class HydroturbinePersistenceTest { turbine.readAdditionalSaveData(source); CompoundTag saved = new CompoundTag(); turbine.addAdditionalSaveData(saved); - assertArrayEquals(new int[] {164, 81, 8}, saved.getIntArray("parentPos")); + assertArrayEquals(new int[] {164, 81, 8}, saved.getIntArray("parentPos").orElseThrow()); source = saved; } } @@ -49,7 +49,7 @@ public class HydroturbinePersistenceTest { turbine.readAdditionalSaveData(new CompoundTag()); CompoundTag saved = new CompoundTag(); turbine.addAdditionalSaveData(saved); - assertFalse(saved.contains("parentPos", 11)); + assertFalse((saved.get("parentPos") instanceof net.minecraft.nbt.IntArrayTag)); } @Test public void savesAttachedGeneratorUsingTheSameLegacyCoordinateKey() throws Exception { @@ -58,7 +58,7 @@ public class HydroturbinePersistenceTest { turbine.parent = generator; CompoundTag saved = new CompoundTag(); turbine.addAdditionalSaveData(saved); - assertArrayEquals(new int[] {31, 72, -18}, saved.getIntArray("parentPos")); + assertArrayEquals(new int[] {31, 72, -18}, saved.getIntArray("parentPos").orElseThrow()); } @Test public void malformedLegacyCoordinatesDoNotCreateAPartialParentLink() throws Exception { @@ -68,7 +68,7 @@ public class HydroturbinePersistenceTest { turbine.readAdditionalSaveData(source); CompoundTag saved = new CompoundTag(); turbine.addAdditionalSaveData(saved); - assertFalse(saved.contains("parentPos", 11)); + assertFalse((saved.get("parentPos") instanceof net.minecraft.nbt.IntArrayTag)); } // Only exercise the custom NBT methods; no world, registry or entity tick is needed. diff --git a/src/test/java/zone/moddev/mc/baseelectric/graphics/RendererBufferContractTest.java b/src/test/java/zone/moddev/mc/baseelectric/graphics/RendererBufferContractTest.java index 926ff6ab..c410f592 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/graphics/RendererBufferContractTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/graphics/RendererBufferContractTest.java @@ -10,7 +10,7 @@ import java.util.List; import net.minecraft.client.renderer.MultiBufferSource; import org.joml.Matrix4f; -import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.rendertype.RenderType; import com.mojang.math.Axis; import net.minecraft.core.Direction; import zone.moddev.mc.baseelectric.verification.NativeTestBootstrap; @@ -69,7 +69,7 @@ public class RendererBufferContractTest { renderer.render(drill, 0.5F, matrices, buffer, 0, 17); assertSame(before, matrices.last()); assertEquals(matrix, matrices.last().pose()); - assertTrue(matrices.clear()); + assertTrue(matrices.isEmpty()); assertEquals(direction.toString(), 16, buffer.vertices.size()); assertArrayEquals(new float[] {11.5F, -4.5F, 7.5F}, midpoint(buffer.vertices.get(0), buffer.vertices.get(3)), 0.00001F); @@ -91,7 +91,7 @@ public class RendererBufferContractTest { RecordingBuffer buffer = new RecordingBuffer(); new LaserDrillRenderer(null).render(new ElectricDrillTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state(ElectricDrillBlock.class)), 0, matrices, buffer, 0, 0); assertSame(before, matrices.last()); - assertTrue(matrices.clear()); + assertTrue(matrices.isEmpty()); assertTrue(buffer.vertices.isEmpty()); } @@ -112,7 +112,7 @@ public class RendererBufferContractTest { assertEquals(beam ? 40 : 24, buffer.vertices.size()); assertSame(before, matrices.last()); assertEquals(matrix, before.pose()); - assertTrue(matrices.clear()); + assertTrue(matrices.isEmpty()); assertArrayEquals(new float[] {0.5F, 0.5F}, buffer.vertices.get(0).uv, 0F); assertArrayEquals(new float[] {1, 1}, buffer.vertices.get(2).uv, 0F); for (int i = 0; i < buffer.vertices.size(); i++) { @@ -194,9 +194,11 @@ private static final class RecordingBuffer implements VertexConsumer, MultiBuffe return this; } @Override public VertexConsumer setColor(int r, int g, int b, int a) { vertex.color = new int[] {r, g, b, a}; return this; } + @Override public VertexConsumer setColor(int color) { return setColor(color >> 16 & 255, color >> 8 & 255, color & 255, color >>> 24); } @Override public VertexConsumer setUv(float u, float v) { vertex.uv = new float[] {u, v}; return this; } @Override public VertexConsumer setUv1(int u, int v) { vertex.overlay = u | v << 16; return this; } @Override public VertexConsumer setUv2(int u, int v) { vertex.light = u | v << 16; return this; } @Override public VertexConsumer setNormal(float x, float y, float z) { vertex.normal = new float[] {x, y, z}; return this; } + @Override public VertexConsumer setLineWidth(float width) { throw new AssertionError("Entity quads must not emit line width"); } } } diff --git a/src/test/java/zone/moddev/mc/baseelectric/init/VillagesTest.java b/src/test/java/zone/moddev/mc/baseelectric/init/VillagesTest.java index 9f036bad..f0ed429f 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/init/VillagesTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/init/VillagesTest.java @@ -34,16 +34,18 @@ private static void assertOffer(int minimum, int maximum, boolean upper, int eme @Override public int nextInt(int bound) { return upper ? bound - 1 : 0; } }; MerchantOffer offer = Villages.sell(net.minecraft.world.item.Items.APPLE, minimum, maximum) - .getOffer(null, random); + .getOffer(null, null, random); CompoundTag nbt = (CompoundTag) MerchantOffer.CODEC.encodeStart( NativeTestBootstrap.registries().createSerializationContext(NbtOps.INSTANCE), offer).getOrThrow(); - assertEquals("minecraft:emerald", nbt.getCompound("buy").getString("id")); - CompoundTag payment = nbt.getCompound("buy"); - assertEquals(emeralds, payment.contains("count") ? payment.getInt("count") : 1); - assertEquals("minecraft:apple", nbt.getCompound("sell").getString("id")); - CompoundTag sale = nbt.getCompound("sell"); - assertEquals(goods, sale.contains("count") ? sale.getInt("count") : 1); - assertEquals(7, nbt.getInt("maxUses")); - assertEquals(0.0F, nbt.getFloat("priceMultiplier"), 0.0F); + assertEquals("minecraft:emerald", nbt.getCompound("buy").orElseThrow().getString("id").orElseThrow()); + CompoundTag payment = nbt.getCompound("buy").orElseThrow(); + assertEquals(emeralds, payment.contains("count") ? payment.getInt("count").orElseThrow() : 1); + assertEquals("minecraft:apple", nbt.getCompound("sell").orElseThrow().getString("id").orElseThrow()); + CompoundTag sale = nbt.getCompound("sell").orElseThrow(); + assertEquals(goods, sale.contains("count") ? sale.getInt("count").orElseThrow() : 1); + assertEquals(7, nbt.getInt("maxUses").orElseThrow().intValue()); + assertEquals(0.0F, offer.getPriceMultiplier(), 0.0F); + // Native MerchantOffer.CODEC omits its zero price-multiplier default. + assertEquals(0.0F, nbt.getFloatOr("priceMultiplier", 0.0F), 0.0F); } } diff --git a/src/test/java/zone/moddev/mc/baseelectric/items/BatteryComponentTest.java b/src/test/java/zone/moddev/mc/baseelectric/items/BatteryComponentTest.java index d20473f1..e6dcf1bd 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/items/BatteryComponentTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/items/BatteryComponentTest.java @@ -16,21 +16,21 @@ public class BatteryComponentTest { @Test public void vanillaItemUpgradePreservesDepletedChargeAndUnrelatedData() { CompoundTag custom = LegacyBatteryDataTest.upgradeBattery() - .getCompound("components").getCompound("minecraft:custom_data"); + .getCompound("components").orElseThrow().getCompound("minecraft:custom_data").orElseThrow(); - BatteryItem battery = new BatteryItem(100, new Item.Properties()); + BatteryItem battery = new BatteryItem(100, new Item.Properties().setId(zone.moddev.mc.baseelectric.util.RegistryIds.item("lead_acid_battery"))); ItemStack stack = new ItemStack(battery); assertEquals(100, battery.getEnergy(stack), 0); stack.set(DataComponents.CUSTOM_DATA, CustomData.of(custom)); assertEquals(0, battery.getEnergy(stack), 0); assertEquals(100, battery.addEnergy(stack, 125, Power.ELECTRIC_POWER), 0); - assertEquals("preserved", stack.get(DataComponents.CUSTOM_DATA).copyTag().getString("probe")); + assertEquals("preserved", stack.get(DataComponents.CUSTOM_DATA).copyTag().getString("probe").orElseThrow()); assertEquals(-100, battery.addEnergy(stack, -125, Power.ELECTRIC_POWER), 0); assertEquals(0, battery.getEnergy(stack.copy()), 0); } @Test public void chargeMutationDoesNotLeakIntoAnItemCopy() { - BatteryItem battery = new BatteryItem(100, new Item.Properties()); + BatteryItem battery = new BatteryItem(100, new Item.Properties().setId(zone.moddev.mc.baseelectric.util.RegistryIds.item("lead_acid_battery"))); ItemStack original = new ItemStack(battery); battery.setEnergy(original, 25); ItemStack copy = original.copy(); diff --git a/src/test/java/zone/moddev/mc/baseelectric/items/LegacyBatteryDataTest.java b/src/test/java/zone/moddev/mc/baseelectric/items/LegacyBatteryDataTest.java index 97b28ece..5b398aa5 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/items/LegacyBatteryDataTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/items/LegacyBatteryDataTest.java @@ -13,12 +13,13 @@ public class LegacyBatteryDataTest { @Test public void nativeDataFixerKeepsTheModdedItemAndMovesItsLegacyCharge() { CompoundTag upgraded = upgradeBattery(); - assertEquals("baseelectric:lead_acid_battery", upgraded.getString("id")); + assertEquals("baseelectric:lead_acid_battery", upgraded.getString("id").orElseThrow()); assertFalse(upgraded.contains("tag")); - CompoundTag custom = upgraded.getCompound("components").getCompound("minecraft:custom_data"); + CompoundTag custom = upgraded.getCompound("components").orElseThrow() + .getCompound("minecraft:custom_data").orElseThrow(); assertTrue("Zero charge must be explicitly preserved", custom.contains("energy")); - assertEquals(0, custom.getFloat("energy"), 0); - assertEquals("preserved", custom.getString("probe")); + assertEquals(0, custom.getFloat("energy").orElseThrow(), 0); + assertEquals("preserved", custom.getString("probe").orElseThrow()); } static CompoundTag upgradeBattery() { @@ -32,6 +33,6 @@ static CompoundTag upgradeBattery() { item.put("tag", tag); return (CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, new Dynamic<>(NbtOps.INSTANCE, item), 3465, - SharedConstants.getCurrentVersion().getDataVersion().getVersion()).getValue(); + SharedConstants.getCurrentVersion().dataVersion().version()).getValue(); } } diff --git a/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricDrillPersistenceTest.java b/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricDrillPersistenceTest.java index 7360f001..019354f4 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricDrillPersistenceTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricDrillPersistenceTest.java @@ -27,15 +27,15 @@ public class ElectricDrillPersistenceTest { @Test public void retainsLegacyProgressUntilWorldIsAttached() { ElectricDrillTileEntity drill = new ElectricDrillTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state(ElectricDrillBlock.class)); - drill.loadWithComponents(target(94), NativeTestBootstrap.registries()); + drill.loadWithComponents(NativeTestBootstrap.input(target(94))); drill.prepareDataFieldsForSync(); assertEquals(94, drill.getDataFieldArray()[1]); } @Test public void clearsPreviousProgressOnReadingAnUntargetedTile() { ElectricDrillTileEntity drill = new ElectricDrillTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state(ElectricDrillBlock.class)); - drill.loadWithComponents(target(94), NativeTestBootstrap.registries()); - drill.loadWithComponents(new CompoundTag(), NativeTestBootstrap.registries()); + drill.loadWithComponents(NativeTestBootstrap.input(target(94))); + drill.loadWithComponents(NativeTestBootstrap.input(new CompoundTag())); drill.prepareDataFieldsForSync(); assertEquals(0, drill.getDataFieldArray()[1]); } @@ -81,7 +81,7 @@ public class ElectricDrillPersistenceTest { @Test public void nativeDataFieldsRetainEnergyAndMiningProgress() { ElectricDrillTileEntity drill = new ElectricDrillTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state(ElectricDrillBlock.class)); - drill.loadWithComponents(target(94), NativeTestBootstrap.registries()); + drill.loadWithComponents(NativeTestBootstrap.input(target(94))); drill.setEnergy(416.0F, drill.getEnergyType()); drill.prepareDataFieldsForSync(); assertEquals(416.0F, Float.intBitsToFloat(drill.getDataFieldArray()[0]), 0.0F); @@ -104,16 +104,16 @@ public class ElectricDrillPersistenceTest { oldItems.add(oldStack); CompoundTag legacy = target(94); legacy.put("Items", oldItems); - drill.loadWithComponents(legacy, NativeTestBootstrap.registries()); + drill.loadWithComponents(NativeTestBootstrap.input(legacy)); drill.setEnergy(416.0F, drill.getEnergyType()); ItemStack payload = drill.getOutputSlot(0); assertEquals(Items.DIAMOND, payload.getItem()); assertEquals(3, payload.getCount()); assertEquals(Component.literal("Track transfer payload"), payload.get(DataComponents.CUSTOM_NAME)); CompoundTag transfer = drill.saveWithoutMetadata(NativeTestBootstrap.registries()); - assertEquals(94, transfer.getShort("progress")); + assertEquals(94, transfer.getShort("progress").orElseThrow().shortValue()); ElectricDrillTileEntity placed = new ElectricDrillTileEntity(new BlockPos(5, 70, 9), drill.getBlockState()); - placed.loadWithComponents(transfer, NativeTestBootstrap.registries()); + placed.loadWithComponents(NativeTestBootstrap.input(transfer)); assertEquals(416.0F, placed.getEnergy(placed.getEnergyType()), 0.0F); assertEquals(new BlockPos(5, 70, 9), placed.getBlockPos()); assertEquals(3, placed.getOutputSlot(0).getCount()); diff --git a/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalNativeDefectsTest.java b/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalNativeDefectsTest.java index 44d03a15..c6d114cd 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalNativeDefectsTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalNativeDefectsTest.java @@ -113,7 +113,7 @@ private static final class LightWorld extends ServerLevel { BlockPos surface; int brightness, skyReads, lightReads; private LightWorld() { - super(null, null, null, null, null, null, null, false, 0L, Collections.emptyList(), false, null); + super(null, null, null, null, null, null, false, 0L, Collections.emptyList(), false, null); } @Override public boolean canSeeSky(BlockPos pos) { assertEquals("Sky access must be sampled above the solid panel", surface, pos); @@ -131,7 +131,7 @@ private static final class BeamWorld extends ServerLevel { BlockPos turret; int traces; private BeamWorld() { - super(null, null, null, null, null, null, null, false, 0L, Collections.emptyList(), false, null); + super(null, null, null, null, null, null, false, 0L, Collections.emptyList(), false, null); } @Override public BlockHitResult clip(ClipContext context) { traces++; diff --git a/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalPumpPickupTest.java b/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalPumpPickupTest.java index b6fe45e8..0694b35a 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalPumpPickupTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalPumpPickupTest.java @@ -184,7 +184,7 @@ private static final class PumpWorld extends ServerLevel { Map blocks; int writes; private PumpWorld() { - super(null, null, null, null, null, null, null, false, 0L, Collections.emptyList(), false, null); + super(null, null, null, null, null, null, false, 0L, Collections.emptyList(), false, null); } @Override public boolean hasChunkAt(BlockPos pos) { return true; } @Override public BlockState getBlockState(BlockPos pos) { @@ -203,12 +203,12 @@ private static final class RefusingSource extends Block implements BucketPickup final boolean returnNull; int calls; RefusingSource(boolean returnNull) { - super(Block.Properties.of().mapColor(MapColor.STONE)); + super(Block.Properties.of().setId(zone.moddev.mc.baseelectric.util.RegistryIds.block("test_refusing_source")).mapColor(MapColor.STONE)); this.returnNull = returnNull; defaultBlockState().initCache(); } @Override public FluidState getFluidState(BlockState state) { return Fluids.WATER.getSource(false); } - @Override public net.minecraft.world.item.ItemStack pickupBlock(net.minecraft.world.entity.player.Player player, LevelAccessor world, BlockPos pos, BlockState state) { + @Override public net.minecraft.world.item.ItemStack pickupBlock(net.minecraft.world.entity.LivingEntity player, LevelAccessor world, BlockPos pos, BlockState state) { calls++; return returnNull ? null : net.minecraft.world.item.ItemStack.EMPTY; } diff --git a/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalRedstoneCacheTest.java b/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalRedstoneCacheTest.java index f740cc5d..35ab6e6e 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalRedstoneCacheTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalRedstoneCacheTest.java @@ -58,7 +58,7 @@ public class ElectricOperationalRedstoneCacheTest { Field clientSide = Level.class.getDeclaredField("isClientSide"); clientSide.setAccessible(true); clientSide.setBoolean(client, true); - assertTrue(client.isClientSide); + assertTrue(client.isClientSide()); assertFalse(machine.signal()); client.signalled = false; assertFalse(machine.signal()); @@ -208,7 +208,7 @@ private static final class SignalWorld extends ServerLevel { long time; List queryTimes; private SignalWorld() { - super(null, null, null, null, null, null, null, false, 0L, Collections.emptyList(), false, null); + super(null, null, null, null, null, null, false, 0L, Collections.emptyList(), false, null); } @Override public boolean hasNeighborSignal(BlockPos position) { assertEquals(this.position, position); diff --git a/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalSoundBroadcastTest.java b/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalSoundBroadcastTest.java index d8e8b9c1..9c5bc623 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalSoundBroadcastTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/machines/ElectricOperationalSoundBroadcastTest.java @@ -112,7 +112,7 @@ private static final class QueryRejectingWorld extends ServerLevel { int playerListReads; private QueryRejectingWorld() { - super(null, null, null, null, null, null, null, false, 0L, Collections.emptyList(), false, null); + super(null, null, null, null, null, null, false, 0L, Collections.emptyList(), false, null); } @Override public List players() { diff --git a/src/test/java/zone/moddev/mc/baseelectric/machines/GrowthChamberPersistenceTest.java b/src/test/java/zone/moddev/mc/baseelectric/machines/GrowthChamberPersistenceTest.java index becd4d25..a5505af8 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/machines/GrowthChamberPersistenceTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/machines/GrowthChamberPersistenceTest.java @@ -17,10 +17,10 @@ public class GrowthChamberPersistenceTest { source.putIntArray("prog", new int[] {245, 468, 627}); for (int pass = 0; pass < 3; pass++) { GrowthChamberTileEntity chamber = new GrowthChamberTileEntity(net.minecraft.core.BlockPos.ZERO, NativeMachineFixture.state(GrowthChamberBlock.class)); - chamber.loadWithComponents(source, NativeTestBootstrap.registries()); + chamber.loadWithComponents(NativeTestBootstrap.input(source)); CompoundTag saved = chamber.saveWithoutMetadata(NativeTestBootstrap.registries()); - assertArrayEquals(new byte[] {2, 4, 6}, saved.getByteArray("growth")); - assertArrayEquals(new int[] {245, 468, 627}, saved.getIntArray("prog")); + assertArrayEquals(new byte[] {2, 4, 6}, saved.getByteArray("growth").orElseThrow()); + assertArrayEquals(new int[] {245, 468, 627}, saved.getIntArray("prog").orElseThrow()); source = saved; } } @@ -33,11 +33,11 @@ public class GrowthChamberPersistenceTest { chamber.loadFrom(source); CompoundTag saved = new CompoundTag(); chamber.saveTo(saved); - assertArrayEquals(new byte[] {2, 0, 0}, saved.getByteArray("growth")); - assertArrayEquals(new int[] {245, 0, 0}, saved.getIntArray("prog")); + assertArrayEquals(new byte[] {2, 0, 0}, saved.getByteArray("growth").orElseThrow()); + assertArrayEquals(new int[] {245, 0, 0}, saved.getIntArray("prog").orElseThrow()); chamber.loadFrom(new CompoundTag()); chamber.saveTo(saved); - assertArrayEquals(new byte[] {0, 0, 0}, saved.getByteArray("growth")); - assertArrayEquals(new int[] {0, 0, 0}, saved.getIntArray("prog")); + assertArrayEquals(new byte[] {0, 0, 0}, saved.getByteArray("growth").orElseThrow()); + assertArrayEquals(new int[] {0, 0, 0}, saved.getIntArray("prog").orElseThrow()); } } diff --git a/src/test/java/zone/moddev/mc/baseelectric/machines/Native118ConstructionTest.java b/src/test/java/zone/moddev/mc/baseelectric/machines/Native118ConstructionTest.java index eaeeeda3..ccd543bb 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/machines/Native118ConstructionTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/machines/Native118ConstructionTest.java @@ -33,7 +33,7 @@ public class Native118ConstructionTest { assertTrue(tile.getType().isValid(state)); CompoundTag saved = new CompoundTag(); saved.putInt("x", 0); saved.putInt("y", 1); saved.putInt("z", 2); - tile.loadWithComponents(saved, NativeTestBootstrap.registries()); + tile.loadWithComponents(NativeTestBootstrap.input(saved)); assertEquals("NBT coordinates cannot move a native block entity", pos, tile.getBlockPos()); assertSame(state, tile.getBlockState()); } @@ -42,7 +42,7 @@ public class Native118ConstructionTest { @Test public void turretPacketUsesConstructorCoordinatesBeforeWorldAttachment() throws Exception { BlockPos pos = new BlockPos(1531, 91, -475); LaserTurretBlock block = new LaserTurretBlock(false); - BlockEntityType type = BlockEntityType.Builder.of(LaserTurretTileEntity::new, block).build(null); + BlockEntityType type = new BlockEntityType<>(LaserTurretTileEntity::new, java.util.Set.of(block)); BlockEntityType previous = zone.moddev.mc.baseelectric.init.Entities.LASER_TURRET; try { zone.moddev.mc.baseelectric.init.Entities.LASER_TURRET = type; @@ -61,7 +61,7 @@ public class Native118ConstructionTest { var packet = turret.getUpdatePacket(); assertEquals(pos, packet.getPos()); assertSame(type, packet.getType()); - assertEquals(java.util.Set.of("energy", "lock"), packet.getTag().getAllKeys()); + assertEquals(java.util.Set.of("energy", "lock"), packet.getTag().keySet()); } finally { zone.moddev.mc.baseelectric.init.Entities.LASER_TURRET = previous; } @@ -69,7 +69,7 @@ public class Native118ConstructionTest { private static final class PacketWorld extends ServerLevel { private PacketWorld() { - super(null, null, null, null, null, null, null, false, 0L, java.util.List.of(), false, null); + super(null, null, null, null, null, null, false, 0L, java.util.List.of(), false, null); } @Override public RegistryAccess registryAccess() { @@ -79,7 +79,7 @@ private PacketWorld() { @Test public void ledOnlyOffersItsOwnNativeTicker() { LEDBlock block = new LEDBlock(); - BlockEntityType type = BlockEntityType.Builder.of(LEDTileEntity::new, block).build(null); + BlockEntityType type = new BlockEntityType<>(LEDTileEntity::new, java.util.Set.of(block)); BlockEntityType previous = zone.moddev.mc.baseelectric.init.Entities.LED; try { zone.moddev.mc.baseelectric.init.Entities.LED = type; diff --git a/src/test/java/zone/moddev/mc/baseelectric/resources/BaseMetalsRawRecipeContractTest.java b/src/test/java/zone/moddev/mc/baseelectric/resources/BaseMetalsRawRecipeContractTest.java index 479b397f..878bee9b 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/resources/BaseMetalsRawRecipeContractTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/resources/BaseMetalsRawRecipeContractTest.java @@ -19,8 +19,8 @@ public class BaseMetalsRawRecipeContractTest { assertNotNull(path, stream); JsonObject recipe = new JsonParser().parse(new InputStreamReader(stream, StandardCharsets.UTF_8)).getAsJsonObject(); assertEquals("basemetals:crushing", recipe.get("type").getAsString()); - assertEquals("forge:" + (input.equals("ore") ? "ores/" : "raw_materials/") + metal, - recipe.getAsJsonObject("ingredient").get("tag").getAsString()); + assertEquals("#forge:" + (input.equals("ore") ? "ores/" : "raw_materials/") + metal, + recipe.get("ingredient").getAsString()); assertEquals("basemetals:" + metal + "_powder", recipe.getAsJsonObject("result").get("id").getAsString()); // The native item stack codec defaults an omitted count to one. assertEquals(input.equals("ore") ? 2 : 1, GsonHelper.getAsInt(recipe.getAsJsonObject("result"), "count", 1)); diff --git a/src/test/java/zone/moddev/mc/baseelectric/resources/BlockLootResourceTest.java b/src/test/java/zone/moddev/mc/baseelectric/resources/BlockLootResourceTest.java index 3743ca10..0b0c5371 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/resources/BlockLootResourceTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/resources/BlockLootResourceTest.java @@ -35,11 +35,50 @@ public class BlockLootResourceTest { @Test public void resourcePackDeclaresTheNativeOneTwentyOneFormat() throws Exception { JsonObject pack = read(Paths.get("src/main/resources/pack.mcmeta")).getAsJsonObject("pack"); - assertEquals(34, pack.get("pack_format").getAsInt()); - JsonObject formats = pack.getAsJsonObject("supported_formats"); - assertEquals(34, formats.get("min_inclusive").getAsInt()); - assertEquals(48, formats.get("max_inclusive").getAsInt()); + assertEquals(JsonParser.parseString("[94,1]"), pack.get("min_format")); + assertEquals(JsonParser.parseString("[94,1]"), pack.get("max_format")); + assertFalse(pack.has("pack_format")); + assertFalse(pack.has("supported_formats")); assertFalse(pack.has("forge:server_data_pack_format")); + assertTrue(java.util.regex.Pattern.compile("(?m)^showAsResourcePack=false\\r?$") + .matcher(Files.readString(Path.of("src/main/resources/META-INF/mods.toml"))).find()); + zone.moddev.mc.baseelectric.verification.NativeTestBootstrap.initialize(); + var version = net.minecraft.SharedConstants.getCurrentVersion(); + assertEquals(new net.minecraft.server.packs.metadata.pack.PackFormat(75, 0), + version.packVersion(net.minecraft.server.packs.PackType.CLIENT_RESOURCES)); + assertEquals(new net.minecraft.server.packs.metadata.pack.PackFormat(94, 1), + version.packVersion(net.minecraft.server.packs.PackType.SERVER_DATA)); + var proof = zone.moddev.mc.baseelectric.verification.NativePackResourceProof.read(); + assertEquals(0, proof.getAsJsonArray("warningsAndErrors").size()); + for (var type : net.minecraft.server.packs.PackType.values()) { + var side = proof.getAsJsonObject(type.name()); + var metadata = side.getAsJsonObject("nativeMetadata"); + var range = net.minecraft.server.packs.metadata.pack.PackFormat.packCodec(type).codec() + .parse(com.mojang.serialization.JsonOps.INSTANCE, metadata).getOrThrow(); + assertTrue(type.toString(), range.isValueInRange(version.packVersion(type))); + assertEquals("COMPATIBLE", side.get("currentCompatibility").getAsString()); + assertTrue(side.get("resourcesVerified").getAsInt() > 0); + assertFalse(range.isValueInRange(new net.minecraft.server.packs.metadata.pack.PackFormat(74, 0))); + assertFalse(range.isValueInRange(new net.minecraft.server.packs.metadata.pack.PackFormat(95, 0))); + var codec = net.minecraft.server.packs.metadata.pack.PackMetadataSection.forPackType(type).codec(); + var decoded = codec.parse(com.mojang.serialization.JsonOps.INSTANCE, metadata).getOrThrow(); + assertEquals(metadata, codec.encodeStart(com.mojang.serialization.JsonOps.INSTANCE, decoded).getOrThrow()); + } + var client = proof.getAsJsonObject("CLIENT_RESOURCES"); + var server = proof.getAsJsonObject("SERVER_DATA"); + assertEquals("mod_resources", client.get("id").getAsString()); + assertEquals("net.minecraftforge.resource.DelegatingPackResources", client.get("resourcesClass").getAsString()); + assertEquals("mod:baseelectric", server.get("id").getAsString()); + assertEquals("net.minecraft.server.packs.PathPackResources", server.get("resourcesClass").getAsString()); + assertEquals("COMPATIBLE", client.get("loaderCompatibility").getAsString()); + assertEquals("TOO_NEW", server.get("loaderCompatibility").getAsString()); + JsonObject insufficient = pack.deepCopy(); + insufficient.add("min_format", JsonParser.parseString("[75,0]")); + insufficient.remove("pack_format"); + insufficient.remove("supported_formats"); + assertTrue(net.minecraft.server.packs.metadata.pack.PackFormat.packCodec( + net.minecraft.server.packs.PackType.SERVER_DATA).codec() + .parse(com.mojang.serialization.JsonOps.INSTANCE, insufficient).error().isPresent()); } @Test public void eachTrackStateUsesTheNativeCutoutRenderLayer() throws Exception { diff --git a/src/test/java/zone/moddev/mc/baseelectric/resources/BuildWorkflowContractTest.java b/src/test/java/zone/moddev/mc/baseelectric/resources/BuildWorkflowContractTest.java index 91e6bc54..19da6562 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/resources/BuildWorkflowContractTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/resources/BuildWorkflowContractTest.java @@ -42,8 +42,8 @@ public class BuildWorkflowContractTest { } assertTrue(source.contains("ref: ${{ steps.public-pins.outputs.orespawn_ref }}")); assertTrue(source.contains("ref: ${{ steps.public-pins.outputs.power_ref }}")); - assertTrue(source.contains("branches: [master-1.21.1")); - assertTrue(source.contains("-Pforge52MavenizerJar=$MAVENIZER")); + assertTrue(source.contains("branches: [master-1.21.11")); + assertTrue(source.contains("-Pforge61MavenizerJar=$MAVENIZER")); assertTrue(source.contains("-PpowerAdvantageDeobfJar=$POWER_PLAYER")); assertFalse(source.contains("forge47")); if (workflow.equals("ci.yml")) { diff --git a/src/test/java/zone/moddev/mc/baseelectric/resources/NativePackRangeContractTest.java b/src/test/java/zone/moddev/mc/baseelectric/resources/NativePackRangeContractTest.java new file mode 100644 index 00000000..339ae89d --- /dev/null +++ b/src/test/java/zone/moddev/mc/baseelectric/resources/NativePackRangeContractTest.java @@ -0,0 +1,127 @@ +package zone.moddev.mc.baseelectric.resources; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.mojang.serialization.JsonOps; +import java.nio.file.Files; +import java.nio.file.Path; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.metadata.pack.PackFormat; +import org.junit.Test; +import zone.moddev.mc.baseelectric.verification.NativePackResourceProof; +import static org.junit.Assert.*; + +public class NativePackRangeContractTest { + @Test public void pipedDumbTerminalChildUsesOfficialNonInteractiveFlag() throws Exception { + Path root = Path.of("build/native-pack-resources").toAbsolutePath(); + Files.createDirectories(root); + Path evidence = Files.createTempDirectory(root, "piped-dumb-"); + var builder = NativePackResourceProof.childProcess(evidence); + assertEquals("dumb", builder.environment().get("TERM")); + assertEquals("terminal.jline", net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY); + assertEquals(ProcessBuilder.Redirect.PIPE, builder.redirectInput()); + assertEquals(ProcessBuilder.Redirect.PIPE, builder.redirectOutput()); + assertTrue(builder.redirectErrorStream()); + Process child = builder.start(); + child.getOutputStream().close(); + var output = java.util.concurrent.CompletableFuture.supplyAsync(() -> { + try { + return new String(child.getInputStream().readAllBytes(), java.nio.charset.StandardCharsets.UTF_8); + } catch (java.io.IOException failure) { + throw new java.io.UncheckedIOException(failure); + } + }); + try { + assertTrue("Piped native proof timed out", child.waitFor(90, java.util.concurrent.TimeUnit.SECONDS)); + String log = output.get(10, java.util.concurrent.TimeUnit.SECONDS); + Path logPath = evidence.resolve("piped-resources.log"); + Files.writeString(logPath, log); + assertEquals(log, 0, child.exitValue()); + NativePackResourceProof.requireNoDiagnostics(logPath, log); + JsonObject proof = JsonParser.parseString(Files.readString(evidence.resolve("receipt.json"))).getAsJsonObject(); + var property = proof.get("terminalJline"); + assertEquals("Native child must disable JLine using the official property", "false", + property.isJsonNull() ? null : property.getAsString()); + assertFalse(proof.get("terminalPresent").getAsBoolean()); + assertTrue(proof.get("interactiveTerminalDisabled").getAsBoolean()); + assertEquals(0, proof.getAsJsonArray("warningsAndErrors").size()); + assertTrue(proof.getAsJsonObject("CLIENT_RESOURCES").get("resourcesVerified").getAsInt() > 0); + assertTrue(proof.getAsJsonObject("SERVER_DATA").get("resourcesVerified").getAsInt() > 0); + } finally { + if (child.isAlive()) child.destroyForcibly().waitFor(); + } + } + + @Test public void nonInteractiveModeDoesNotWhitelistAnyDiagnostic() { + Path log = Path.of("negative-control.log"); + for (String diagnostic : new String[] { + "[main/WARN] real resource warning", "[main/ERROR] real resource error", "[main/FATAL] real fatal", + "2026-11-11T00:00:00Z main WARN Advanced terminal features are not available in this environment", + "2026-11-11T00:00:00Z main ERROR real bootstrap error", "2026-11-11T00:00:00Z main FATAL fatal bootstrap" + }) { + assertThrows(diagnostic, AssertionError.class, + () -> NativePackResourceProof.requireNoDiagnostics(log, diagnostic)); + } + NativePackResourceProof.requireNoDiagnostics(log, "[main/INFO] valid resource receipt"); + } + + @Test public void baseMetalsIsRequiredByNativeModInfoWithOptionalNegativeControl() throws Exception { + var proof = NativePackResourceProof.read(); + assertEquals("net.minecraftforge.fml.loading.moddiscovery.ModInfo", proof.get("modInfoClass").getAsString()); + var dependencies = proof.getAsJsonObject("dependencies"); + assertEquals(java.util.Set.of("forge", "minecraft", "basepower", "basemetals"), dependencies.keySet()); + var metals = dependencies.getAsJsonObject("basemetals"); + assertTrue("Forge must require Base Metals on both sides", metals.get("mandatory").getAsBoolean()); + assertEquals("[3.1.2.121111,4.0.0)", metals.get("versionRange").getAsString()); + assertEquals("AFTER", metals.get("ordering").getAsString()); + assertEquals("BOTH", metals.get("side").getAsString()); + var control = proof.getAsJsonObject("optionalBaseMetalsControl"); + assertFalse("Native ModInfo must detect optional metadata", control.getAsJsonObject("basemetals") + .get("mandatory").getAsBoolean()); + var expectedControl = dependencies.deepCopy(); + expectedControl.getAsJsonObject("basemetals").addProperty("mandatory", false); + assertEquals("Only the control dependency requirement may differ", expectedControl, control); + } + + @Test public void combinedPackRangeAcceptsBothNativePackTypes() throws Exception { + var proof = NativePackResourceProof.read(); + assertEquals(0, proof.getAsJsonArray("warningsAndErrors").size()); + for (PackType type : PackType.values()) { + var side = proof.getAsJsonObject(type.name()); + JsonObject pack = side.getAsJsonObject("nativeMetadata"); + var range = PackFormat.packCodec(type).codec().parse(JsonOps.INSTANCE, pack).getOrThrow(); + assertEquals(type.toString(), type == PackType.CLIENT_RESOURCES, + range.isValueInRange(PackFormat.of(75, 0))); + assertEquals(type.toString(), type == PackType.SERVER_DATA, + range.isValueInRange(PackFormat.of(94, 1))); + assertFalse(range.isValueInRange(PackFormat.of(74))); + assertFalse(range.isValueInRange(PackFormat.of(95))); + } + } + + @Test public void omissionDoesNotSynthesizeMetadataInTheNativeModPathSupplier() throws Exception { + var root = Path.of("build/native-pack-resources").toAbsolutePath(); + Files.createDirectories(root); + var omitted = Files.createTempDirectory(root, "missing-metadata-"); + var info = new net.minecraft.server.packs.PackLocationInfo("mod:baseelectric", + net.minecraft.network.chat.Component.literal("baseElectric"), + net.minecraft.server.packs.repository.PackSource.DEFAULT, java.util.Optional.empty()); + var supplier = new net.minecraft.server.packs.PathPackResources.PathResourcesSupplier(omitted); + try (var resources = supplier.openPrimary(info)) { + assertNull(resources.getRootResource("pack.mcmeta")); + for (PackType type : PackType.values()) { + assertNull(type.toString(), resources.getMetadataSection( + net.minecraft.server.packs.metadata.pack.PackMetadataSection.forPackType(type))); + } + } + } + + @Test public void dataOnlyRangeDoesNotQualifyClientResources() { + JsonObject dataOnly = JsonParser.parseString("{\"min_format\":[94,1],\"max_format\":[94,1]}") + .getAsJsonObject(); + var range = PackFormat.packCodec(PackType.CLIENT_RESOURCES).codec() + .parse(JsonOps.INSTANCE, dataOnly).getOrThrow(); + assertFalse(range.isValueInRange(PackFormat.of(75, 0))); + assertTrue(range.isValueInRange(PackFormat.of(94, 1))); + } +} diff --git a/src/test/java/zone/moddev/mc/baseelectric/resources/RecipeRegistrationThreadTest.java b/src/test/java/zone/moddev/mc/baseelectric/resources/RecipeRegistrationThreadTest.java index 936b95f1..552b01f9 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/resources/RecipeRegistrationThreadTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/resources/RecipeRegistrationThreadTest.java @@ -10,7 +10,8 @@ public class RecipeRegistrationThreadTest { Path root = Path.of("src/main/java/zone/moddev/mc/baseelectric"); String entry = Files.readString(root.resolve("ElectricAdvantage.java")); String conditions = Files.readString(root.resolve("recipe/RecipeConditions.java")); - assertTrue(entry.contains("RecipeConditions.register(context.getModEventBus())")); + assertTrue(entry.contains("var bus = context.getModBusGroup()")); + assertTrue(entry.contains("RecipeConditions.register(bus)")); assertFalse(entry.contains("RecipeConditions::register")); assertTrue(conditions.contains("DeferredRegister.create(ForgeRegistries.Keys.CONDITION_SERIALIZERS")); assertTrue(conditions.contains("SERIALIZERS.register(bus)")); diff --git a/src/test/java/zone/moddev/mc/baseelectric/resources/RecipeResourceTest.java b/src/test/java/zone/moddev/mc/baseelectric/resources/RecipeResourceTest.java index 71d393c3..985b1a9b 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/resources/RecipeResourceTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/resources/RecipeResourceTest.java @@ -18,7 +18,8 @@ import org.junit.Test; public class RecipeResourceTest { - @Test public void allRecipesUseTheNativeOneFifteenDataPackLocationAndSerializers() throws IOException { + @Test public void allRecipesUseTheNativeOneFifteenDataPackLocationAndSerializers() throws Exception { + assertNativeCodecShapes(); Path recipes = Paths.get("src/main/resources/data/baseelectric/recipe"); List files; try (Stream stream = Files.list(recipes)) { @@ -31,8 +32,8 @@ public class RecipeResourceTest { String text = new String(Files.readAllBytes(file), StandardCharsets.UTF_8); JsonObject json = new JsonParser().parse(text).getAsJsonObject(); String type = json.get("type").getAsString(); - assertTrue(file + " must use the 1.21.1 result stack codec", json.getAsJsonObject("result").has("id")); - assertFalse(file + " still has pre-1.21.1 Forge conditions", json.has("conditions")); + assertTrue(file + " must use the 1.21.11 result stack codec", json.getAsJsonObject("result").has("id")); + assertFalse(file + " still has pre-1.21.11 Forge conditions", json.has("conditions")); assertTrue(file + " has unsupported serializer " + type, "minecraft:crafting_shaped".equals(type) || "minecraft:crafting_shapeless".equals(type) @@ -42,10 +43,62 @@ public class RecipeResourceTest { else if ("minecraft:smelting".equals(type)) smelting++; else crushing++; assertFalse(file + " still contains an ore dictionary ingredient", text.contains("ore_dict")); + if (json.has("key")) for (var entry : json.getAsJsonObject("key").entrySet()) + assertNativeIngredient(file, entry.getValue()); + if (json.has("ingredient")) assertNativeIngredient(file, json.get("ingredient")); + if (json.has("ingredients")) assertNativeIngredient(file, json.get("ingredients")); } assertEquals(46, crafting); assertEquals(4, smelting); assertEquals(8, crushing); assertFalse(Files.exists(Paths.get("src/main/resources/assets/baseelectric/recipes"))); } + + private static void assertNativeIngredient(Path file, com.google.gson.JsonElement ingredient) { + if (ingredient.isJsonArray()) { + assertFalse(file.toString(), ingredient.getAsJsonArray().isEmpty()); + for (var value : ingredient.getAsJsonArray()) assertNativeIngredient(file, value); + } else { + assertTrue(file + " must use a native item or #tag string", ingredient.isJsonPrimitive() + && ingredient.getAsJsonPrimitive().isString()); + assertTrue(file.toString(), ingredient.getAsString().matches("#?[a-z0-9_.-]+:[a-z0-9_./-]+")); + } + } + + private static void assertNativeCodecShapes() throws ReflectiveOperationException { + zone.moddev.mc.baseelectric.verification.NativeTestBootstrap.registerVanillaIngredientSerializers(); + // A private native registry scopes this syntax test; live mod IDs are checked by GameTests. + var registry = new net.minecraft.core.MappedRegistry( + net.minecraft.core.registries.Registries.ITEM, com.mojang.serialization.Lifecycle.stable()); + var apple = net.minecraft.core.Registry.registerForHolder(registry, + net.minecraft.resources.Identifier.parse("minecraft:apple"), net.minecraft.world.item.Items.APPLE); + var carrot = net.minecraft.core.Registry.registerForHolder(registry, + net.minecraft.resources.Identifier.parse("minecraft:carrot"), net.minecraft.world.item.Items.CARROT); + registry.freeze(); + var tag = net.minecraft.tags.TagKey.create(net.minecraft.core.registries.Registries.ITEM, + net.minecraft.resources.Identifier.parse("baseelectric:codec_test_choices")); + registry.prepareTagReload(new net.minecraft.tags.TagLoader.LoadResult<>( + net.minecraft.core.registries.Registries.ITEM, java.util.Map.of(tag, + java.util.List.>of(apple, carrot)))).apply(); + var ops = net.minecraft.core.HolderLookup.Provider.create(Stream.of(registry)) + .createSerializationContext(com.mojang.serialization.JsonOps.INSTANCE); + for (String encoded : List.of("\"minecraft:apple\"", + "[\"minecraft:apple\",\"minecraft:carrot\"]", "\"#baseelectric:codec_test_choices\"")) { + var ingredient = net.minecraft.world.item.crafting.Ingredient.CODEC.parse(ops, + JsonParser.parseString(encoded)).getOrThrow(); + assertEquals(encoded, encoded.equals("\"minecraft:apple\"") + ? List.of(net.minecraft.world.item.Items.APPLE) + : List.of(net.minecraft.world.item.Items.APPLE, net.minecraft.world.item.Items.CARROT), + ingredient.items().map(net.minecraft.core.Holder::value).toList()); + var roundTrip = net.minecraft.world.item.crafting.Ingredient.CODEC.parse(ops, + net.minecraft.world.item.crafting.Ingredient.CODEC.encodeStart(ops, ingredient).getOrThrow()).getOrThrow(); + assertEquals(ingredient, roundTrip); + } + for (String obsolete : List.of("{\"item\":\"minecraft:apple\"}", + "{\"tag\":\"baseelectric:codec_test_choices\"}")) { + assertTrue("Forge 61 must reject old ingredient objects: " + obsolete, + net.minecraft.world.item.crafting.Ingredient.CODEC.parse(ops, + JsonParser.parseString(obsolete)).error().isPresent()); + } + } } diff --git a/src/test/java/zone/moddev/mc/baseelectric/resources/RecipeUnlockContractTest.java b/src/test/java/zone/moddev/mc/baseelectric/resources/RecipeUnlockContractTest.java index 57297209..1589deea 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/resources/RecipeUnlockContractTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/resources/RecipeUnlockContractTest.java @@ -19,7 +19,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import com.mojang.serialization.JsonOps; -import net.minecraft.advancements.critereon.ItemPredicate; +import net.minecraft.advancements.criterion.ItemPredicate; import net.minecraft.world.item.Items; import org.junit.Test; import static org.junit.Assert.*; @@ -164,7 +164,12 @@ private static String unlockPredicateKey(JsonObject predicate) { private static void collect(JsonElement element, List result) { if (element.isJsonArray()) for (JsonElement child : element.getAsJsonArray()) collect(child, result); - else result.add(element.getAsJsonObject()); + else if (element.isJsonPrimitive()) { + String id = element.getAsString(); + JsonObject choice = new JsonObject(); + choice.addProperty(id.startsWith("#") ? "tag" : "item", id.startsWith("#") ? id.substring(1) : id); + result.add(choice); + } else result.add(element.getAsJsonObject()); } private static JsonObject read(Path file) throws IOException { diff --git a/src/test/java/zone/moddev/mc/baseelectric/resources/ShaderResourceContractTest.java b/src/test/java/zone/moddev/mc/baseelectric/resources/ShaderResourceContractTest.java index b07c9177..bf619229 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/resources/ShaderResourceContractTest.java +++ b/src/test/java/zone/moddev/mc/baseelectric/resources/ShaderResourceContractTest.java @@ -1,44 +1,62 @@ package zone.moddev.mc.baseelectric.resources; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; -import java.util.stream.Collectors; import org.junit.Test; import static org.junit.Assert.*; /** Resource contracts do not prove GPU shader compilation or visual acceptance. */ public class ShaderResourceContractTest { - private static final Path ROOT = Path.of("src/main/resources/assets/baseelectric/shaders/core"); + private static final Path PIPELINES = Path.of( + "src/main/java/zone/moddev/mc/baseelectric/graphics/ElectricRenderTypes.java"); @Test public void nativeShaderRetainsTheEntityVertexLayoutAndVanillaFogFragment() throws Exception { - JsonObject json = new JsonParser().parse(Files.readString(ROOT.resolve("unshaded.json"))).getAsJsonObject(); - assertEquals("baseelectric:unshaded", json.get("vertex").getAsString()); - assertEquals("minecraft:rendertype_entity_translucent", json.get("fragment").getAsString()); - assertEquals(Arrays.asList("Position", "Color", "UV0", "UV1", "UV2", "Normal"), - java.util.stream.StreamSupport.stream(json.getAsJsonArray("attributes").spliterator(), false) - .map(value -> value.getAsString()).collect(Collectors.toList())); - assertNotNull(getClass().getResource("/assets/minecraft/shaders/core/rendertype_entity_translucent.fsh")); - var uniformNames = java.util.stream.StreamSupport.stream(json.getAsJsonArray("uniforms").spliterator(), false) - .map(value -> value.getAsJsonObject().get("name").getAsString()).collect(Collectors.toSet()); - assertTrue(uniformNames.contains("FogShape")); - assertFalse(uniformNames.contains("IViewRotMat")); + String pipeline = Files.readString(PIPELINES); + assertTrue(pipeline.contains("RenderPipelines.ENTITY_SNIPPET")); + assertTrue(pipeline.contains("withShaderDefine(\"NO_CARDINAL_LIGHTING\")")); + assertTrue(pipeline.contains("withSampler(\"Sampler1\")")); + assertTrue(pipeline.contains("withCull(false)")); + assertTrue(pipeline.contains("BlendFunction.TRANSLUCENT")); + assertFalse(pipeline.contains("ShaderInstance")); + assertFalse(pipeline.contains("EMISSIVE")); + assertNotNull(getClass().getResource("/assets/minecraft/shaders/core/entity.fsh")); + String vertex = vanilla("entity.vsh"); + for (String attribute : Arrays.asList("Position", "Color", "UV0", "UV1", "UV2", "Normal")) + assertTrue(attribute, vertex.contains(" " + attribute + ";")); + assertTrue(vertex.contains("dynamictransforms.glsl")); + assertTrue(vertex.contains("projection.glsl")); + assertFalse(vertex.contains("IViewRotMat")); + for (String renderer : Arrays.asList("HydroturbineRenderer", "LaserDrillRenderer", "LaserTurretRenderer")) { + String source = Files.readString(PIPELINES.resolveSibling(renderer + ".java")); + assertFalse("Forge 61 warns about mod-owned class annotations: " + renderer, source.contains("@OnlyIn")); + } + String registration = Files.readString(PIPELINES.resolveSibling("ClientRegistration.java")); + assertTrue(registration.contains("value = Dist.CLIENT")); } @Test public void noDiffuseLightingDoesNotRemoveLightmapOrOverlaySampling() throws Exception { - String vertex = Files.readString(ROOT.resolve("unshaded.vsh")); + String vertex = vanilla("entity.vsh"); assertTrue(vertex.contains("vertexColor = Color;")); assertTrue(vertex.contains("lightMapColor = texelFetch(Sampler2, UV2 / 16, 0);")); assertTrue(vertex.contains("overlayColor = texelFetch(Sampler1, UV1, 0);")); - assertFalse(vertex.contains("minecraft_mix_light")); - assertTrue(vertex.contains("#moj_import ")); - String fog = "vertexDistance = fog_distance(Position, FogShape);"; - assertTrue(vertex.contains(fog)); - try (var vanilla = getClass().getResourceAsStream("/assets/minecraft/shaders/core/rendertype_entity_translucent.vsh")) { - assertNotNull(vanilla); - assertTrue(new String(vanilla.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8).contains(fog)); + assertTrue(vertex.contains("#elif defined(NO_CARDINAL_LIGHTING)\n vertexColor = Color;")); + assertTrue(vertex.contains("#moj_import ")); + assertTrue(vertex.contains("sphericalVertexDistance = fog_spherical_distance(Position);")); + assertTrue(vertex.contains("cylindricalVertexDistance = fog_cylindrical_distance(Position);")); + String fragment = vanilla("entity.fsh"); + assertTrue(fragment.contains("color *= lightMapColor;")); + assertTrue(fragment.contains("mix(overlayColor.rgb, color.rgb, overlayColor.a)")); + assertTrue(fragment.contains("apply_fog(color, sphericalVertexDistance, cylindricalVertexDistance")); + String pipeline = Files.readString(PIPELINES); + assertTrue(pipeline.contains(".useLightmap().useOverlay()")); + assertFalse(pipeline.contains("NO_OVERLAY")); + } + + private static String vanilla(String name) throws Exception { + try (var source = ShaderResourceContractTest.class.getResourceAsStream("/assets/minecraft/shaders/core/" + name)) { + assertNotNull(source); + return new String(source.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8).replace("\r\n", "\n"); } } } diff --git a/src/test/java/zone/moddev/mc/baseelectric/util/crafting/RecipeDeconstructorTest.java b/src/test/java/zone/moddev/mc/baseelectric/util/crafting/RecipeDeconstructorTest.java new file mode 100644 index 00000000..b08b0498 --- /dev/null +++ b/src/test/java/zone/moddev/mc/baseelectric/util/crafting/RecipeDeconstructorTest.java @@ -0,0 +1,59 @@ +package zone.moddev.mc.baseelectric.util.crafting; + +import java.util.List; +import java.util.Map; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.CraftingBookCategory; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.ShapedRecipe; +import net.minecraft.world.item.crafting.ShapedRecipePattern; +import net.minecraft.world.item.crafting.ShapelessRecipe; +import org.junit.BeforeClass; +import org.junit.Test; +import zone.moddev.mc.baseelectric.verification.NativeTestBootstrap; +import static org.junit.Assert.*; + +public class RecipeDeconstructorTest { + @BeforeClass public static void bootstrap() { NativeTestBootstrap.initialize(); } + + @Test public void shapedPlansKeepRepeatedIngredientsAndResultCountWithoutEmptySlots() { + var recipe = new ShapedRecipe("native-plan", CraftingBookCategory.MISC, + ShapedRecipePattern.of(Map.of('A', Ingredient.of(Items.APPLE)), " A ", "AA "), + new ItemStack(Items.GOLDEN_APPLE, 3)); + var plans = RecipeDeconstructor.describe(recipe, NativeTestBootstrap.registries()); + assertEquals(1, plans.size()); + var plan = plans.getFirst(); + assertTrue(plan.result().is(Items.GOLDEN_APPLE)); + assertEquals(3, plan.result().getCount()); + assertEquals(3, plan.ingredients().size()); + for (Ingredient ingredient : plan.ingredients()) { + assertTrue(ingredient.test(new ItemStack(Items.APPLE))); + assertFalse(ingredient.test(new ItemStack(Items.DIRT))); + } + } + + @Test public void shapelessPlansKeepAlternativesAndDoNotInventFreeIngredients() { + var recipe = new ShapelessRecipe("native-plan", CraftingBookCategory.MISC, + new ItemStack(Items.BREAD, 2), List.of(Ingredient.of(Items.APPLE, Items.CARROT), Ingredient.of(Items.WHEAT))); + var plan = RecipeDeconstructor.describe(recipe, NativeTestBootstrap.registries()).getFirst(); + assertEquals(2, plan.ingredients().size()); + assertEquals(2, plan.result().getCount()); + assertTrue(plan.result().is(Items.BREAD)); + assertTrue(plan.ingredients().getFirst().test(new ItemStack(Items.APPLE))); + assertTrue(plan.ingredients().getFirst().test(new ItemStack(Items.CARROT))); + assertFalse(plan.ingredients().getFirst().test(new ItemStack(Items.WHEAT))); + assertTrue(plan.ingredients().get(1).test(new ItemStack(Items.WHEAT))); + var registries = NativeTestBootstrap.registries(); + var original = new net.minecraft.nbt.CompoundTag(); + original.putInt("progress", 127); + original.putIntArray("parentPos", new int[] {31, 72, -18}); + var output = net.minecraft.world.level.storage.TagValueOutput.createWithContext( + net.minecraft.util.ProblemReporter.DISCARDING, registries); + output.store(zone.moddev.mc.baseelectric.util.LegacyNbt.ROOT, original); + assertEquals(original, output.buildResult()); + var input = net.minecraft.world.level.storage.TagValueInput.create( + net.minecraft.util.ProblemReporter.DISCARDING, registries, output.buildResult()); + assertEquals(original, input.read(zone.moddev.mc.baseelectric.util.LegacyNbt.ROOT).orElseThrow()); + } +} diff --git a/src/test/java/zone/moddev/mc/baseelectric/verification/NativeMachineFixture.java b/src/test/java/zone/moddev/mc/baseelectric/verification/NativeMachineFixture.java index 68a9706c..e01e973e 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/verification/NativeMachineFixture.java +++ b/src/test/java/zone/moddev/mc/baseelectric/verification/NativeMachineFixture.java @@ -64,7 +64,7 @@ private void install(String name, BlockEntityType.BlockE Block... validBlocks) throws ReflectiveOperationException { Field field = Entities.class.getField(name); previous.put(field, field.get(null)); - field.set(null, BlockEntityType.Builder.of(factory, validBlocks).build(null)); + field.set(null, new BlockEntityType<>(factory, java.util.Set.of(validBlocks))); for (Block block : validBlocks) blocks.putIfAbsent(block.getClass(), block); allBlocks.addAll(List.of(validBlocks)); } diff --git a/src/test/java/zone/moddev/mc/baseelectric/verification/NativePackResourceProof.java b/src/test/java/zone/moddev/mc/baseelectric/verification/NativePackResourceProof.java new file mode 100644 index 00000000..2b20da4a --- /dev/null +++ b/src/test/java/zone/moddev/mc/baseelectric/verification/NativePackResourceProof.java @@ -0,0 +1,231 @@ +package zone.moddev.mc.baseelectric.verification; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import cpw.mods.jarhandling.SecureJar; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import net.minecraft.SharedConstants; +import net.minecraft.server.Bootstrap; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.PathPackResources; +import net.minecraft.server.packs.metadata.pack.PackMetadataSection; +import net.minecraft.server.packs.repository.Pack; +import net.minecraft.server.packs.repository.PackRepository; +import net.minecraft.server.packs.resources.MultiPackResourceManager; +import net.minecraft.resources.Identifier; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.loading.moddiscovery.ModFile; +import net.minecraftforge.fml.loading.moddiscovery.ModFileParser; +import net.minecraftforge.fml.loading.moddiscovery.ModInfo; +import net.minecraftforge.fml.loading.targets.ForgeDevLocator; +import net.minecraftforge.resource.ResourcePackLoader; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.appender.AbstractAppender; +import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.core.layout.PatternLayout; + +/** Runs real Forge discovery in a child VM so ModList and native registry state cannot leak into other tests. */ +public final class NativePackResourceProof { + private static JsonObject receipt; + + private NativePackResourceProof() {} + + public static synchronized JsonObject read() throws Exception { + if (receipt != null) return receipt.deepCopy(); + Path evidenceRoot = Path.of("build/native-pack-resources").toAbsolutePath(); + Files.createDirectories(evidenceRoot); + Path evidence = Files.createTempDirectory(evidenceRoot, "forge61-"); + Path log = evidence.resolve("forge-resources.log"); + Process process = childProcess(evidence).redirectOutput(log.toFile()).start(); + if (!process.waitFor(90, TimeUnit.SECONDS)) { + process.destroyForcibly().waitFor(); + throw new AssertionError("Native Forge resource proof timed out: " + log); + } + String output = Files.readString(log); + if (process.exitValue() != 0) throw new AssertionError("Native Forge resource proof failed: " + log + "\n" + output); + requireNoDiagnostics(log, output); + receipt = JsonParser.parseString(Files.readString(evidence.resolve("receipt.json"))).getAsJsonObject(); + return receipt.deepCopy(); + } + + public static ProcessBuilder childProcess(Path evidence) { + String classpath = Arrays.stream(System.getProperty("baseelectric.nativePackClasspath", + System.getProperty("java.class.path")).split(java.util.regex.Pattern.quote(java.io.File.pathSeparator))) + .map(entry -> new java.io.File(entry).getAbsolutePath()) + .collect(java.util.stream.Collectors.joining(java.io.File.pathSeparator)); + Path javaExecutable = Path.of(System.getProperty("java.home"), "bin", "java"); + if (!Files.isExecutable(javaExecutable)) javaExecutable = javaExecutable.resolveSibling("java.exe"); + ProcessBuilder process = new ProcessBuilder(javaExecutable.toString(), "-XX:ActiveProcessorCount=4", "-Xmx512m", + "-Dterminal.jline=false", + "--add-opens", "java.base/java.lang.invoke=ALL-UNNAMED", "-cp", classpath, + NativePackResourceProof.class.getName(), Path.of("build/resources/main").toAbsolutePath().toString(), + evidence.toString()).directory(evidence.toFile()) + .redirectErrorStream(true); + process.environment().put("TERM", "dumb"); + return process; + } + + public static void requireNoDiagnostics(Path log, String output) { + if (java.util.regex.Pattern.compile("(?m)(?:\\[[^\\r\\n]*\\b(?:WARN|ERROR|FATAL)\\b[^\\r\\n]*\\]|\\bmain (?:WARN|ERROR|FATAL)\\b)") + .matcher(output).find()) { + throw new AssertionError("Native Forge resource diagnostic in " + log + "\n" + output); + } + } + + public static void main(String[] args) throws Exception { + SharedConstants.tryDetectVersion(); + Bootstrap.bootStrap(); + Path resources = Path.of(args[0]); + Path evidence = Path.of(args[1]); + Path jar = evidence.resolve("baseelectric-resource-contract.jar"); + Manifest manifest = new Manifest(); + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); + manifest.getMainAttributes().putValue("Automatic-Module-Name", "baseelectric"); + try (JarOutputStream output = new JarOutputStream(Files.newOutputStream(jar), manifest); + var files = Files.walk(resources)) { + for (Path file : files.filter(Files::isRegularFile).sorted().toList()) { + output.putNextEntry(new JarEntry(resources.relativize(file).toString().replace('\\', '/'))); + Files.copy(file, output); + output.closeEntry(); + } + } + ModFile mod = new ModFile(SecureJar.from(jar), new ForgeDevLocator(), ModFileParser::modsTomlParser); + if (mod.getModFileInfo().showAsResourcePack()) throw new AssertionError("Electric must use Forge's hidden client pack"); + Path optionalJar = evidence.resolve("baseelectric-optional-basemetals-control.jar"); + String modMetadata = Files.readString(resources.resolve("META-INF/mods.toml")); + var dependency = java.util.regex.Pattern.compile("(modId=\"basemetals\"\\s+mandatory=)(true|false)") + .matcher(modMetadata); + if (!dependency.find()) throw new AssertionError("Missing Base Metals metadata for the negative control"); + try (JarOutputStream output = new JarOutputStream(Files.newOutputStream(optionalJar), manifest)) { + output.putNextEntry(new JarEntry("META-INF/mods.toml")); + output.write(dependency.replaceFirst("$1false").getBytes(StandardCharsets.UTF_8)); + output.closeEntry(); + } + ModFile optionalMod = new ModFile(SecureJar.from(optionalJar), new ForgeDevLocator(), ModFileParser::modsTomlParser); + ModList.of(List.of(mod), mod.getModInfos().stream().map(ModInfo.class::cast).toList()); + List diagnostics = new ArrayList<>(); + AbstractAppender appender = new AbstractAppender("ElectricPackContract", null, + PatternLayout.createDefaultLayout(), false, Property.EMPTY_ARRAY) { + @Override public void append(LogEvent event) { + if (event.getLevel().isMoreSpecificThan(Level.WARN)) diagnostics.add(event.getMessage().getFormattedMessage()); + } + }; + appender.start(); + var logger = (org.apache.logging.log4j.core.Logger)LogManager.getRootLogger(); + logger.addAppender(appender); + JsonObject result = new JsonObject(); + result.addProperty("terminalJline", System.getProperty(net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY)); + result.addProperty("terminalPresent", net.minecrell.terminalconsole.TerminalConsoleAppender.getTerminal() != null); + result.addProperty("interactiveTerminalDisabled", "false".equals(System.getProperty( + net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY)) + && net.minecrell.terminalconsole.TerminalConsoleAppender.getTerminal() == null); + result.addProperty("modInfoClass", mod.getModInfos().getFirst().getClass().getName()); + result.add("dependencies", dependencies(mod)); + result.add("optionalBaseMetalsControl", dependencies(optionalMod)); + try { + for (PackType type : PackType.values()) { + PackRepository repository = new PackRepository(); + ResourcePackLoader.loadResourcePacks(repository, type == PackType.CLIENT_RESOURCES); + repository.reload(); + String id = type == PackType.CLIENT_RESOURCES ? "mod_resources" : "mod:baseelectric"; + if (repository.getAvailableIds().size() != 1 || !repository.isAvailable(id)) { + throw new AssertionError("Unexpected native packs: " + repository.getAvailableIds()); + } + Pack pack = repository.getPack(id); + if (pack == null) throw new AssertionError("Forge did not discover " + id); + JsonObject side = new JsonObject(); + side.addProperty("id", id); + side.addProperty("loaderCompatibility", pack.getCompatibility().name()); + try (var opened = pack.open()) { + PackMetadataSection metadata = opened.getMetadataSection(PackMetadataSection.forPackType(type)); + if (metadata == null) throw new AssertionError("Missing native " + type + " metadata"); + var formats = metadata.supportedFormats(); + var codec = PackMetadataSection.forPackType(type).codec(); + var encoded = codec.encodeStart(com.mojang.serialization.JsonOps.INSTANCE, metadata).getOrThrow(); + var decoded = codec.parse(com.mojang.serialization.JsonOps.INSTANCE, encoded).getOrThrow(); + // Native JSON widens numeric translation arguments; compare the wire value and exact range. + if (!formats.equals(decoded.supportedFormats()) + || !encoded.equals(codec.encodeStart(com.mojang.serialization.JsonOps.INSTANCE, decoded).getOrThrow())) { + throw new AssertionError("Native metadata round-trip changed " + type); + } + side.addProperty("resourcesClass", opened.getClass().getName()); + side.addProperty("acceptsClient", formats.isValueInRange(SharedConstants.getCurrentVersion().packVersion(PackType.CLIENT_RESOURCES))); + side.addProperty("acceptsServer", formats.isValueInRange(SharedConstants.getCurrentVersion().packVersion(PackType.SERVER_DATA))); + side.addProperty("accepts74", formats.isValueInRange(net.minecraft.server.packs.metadata.pack.PackFormat.of(74))); + side.addProperty("accepts95", formats.isValueInRange(net.minecraft.server.packs.metadata.pack.PackFormat.of(95))); + side.add("nativeMetadata", encoded); + if (type == PackType.CLIENT_RESOURCES) { + if (opened.getChildren() == null || opened.getChildren().size() != 1) { + throw new AssertionError("Expected the actual Forge client delegate"); + } + side.addProperty("currentCompatibility", pack.getCompatibility().name()); + } else { + var supplier = new PathPackResources.PathResourcesSupplier(mod.findResource("")); + var current = Pack.readPackMetadata(pack.location(), supplier, + SharedConstants.getCurrentVersion().packVersion(type), type); + if (current == null) throw new AssertionError("Native current-version server metadata was rejected"); + side.addProperty("currentCompatibility", current.compatibility().name()); + } + } + repository.setSelected(List.of(id)); + int checked = 0; + try (MultiPackResourceManager manager = new MultiPackResourceManager(type, repository.openAllSelected()); + var files = Files.walk(resources.resolve(type.getDirectory()))) { + for (Path file : files.filter(Files::isRegularFile).sorted().toList()) { + Path relative = resources.resolve(type.getDirectory()).relativize(file); + String namespace = relative.getName(0).toString(); + String path = relative.subpath(1, relative.getNameCount()).toString().replace('\\', '/'); + var resource = manager.getResource(Identifier.fromNamespaceAndPath(namespace, path)).orElseThrow(); + try (var input = resource.open()) { + if (!Arrays.equals(Files.readAllBytes(file), input.readAllBytes())) { + throw new AssertionError("Forge changed " + type + " resource " + relative); + } + } + checked++; + } + } + if (checked == 0) throw new AssertionError("No native " + type + " resources were read"); + side.addProperty("resourcesVerified", checked); + result.add(type.name(), side); + } + } finally { + logger.removeAppender(appender); + appender.stop(); + } + JsonArray messages = new JsonArray(); + diagnostics.forEach(messages::add); + result.add("warningsAndErrors", messages); + Files.writeString(evidence.resolve("receipt.json"), result.toString(), StandardCharsets.UTF_8); + if (!diagnostics.isEmpty()) throw new AssertionError("Native Forge resource diagnostics: " + diagnostics); + System.out.println("BASEELECTRIC_NATIVE_PACK_RESOURCES_PASS " + result); + } + + private static JsonObject dependencies(ModFile mod) { + ModInfo info = ModInfo.class.cast(mod.getModInfos().stream() + .filter(entry -> entry.getModId().equals("baseelectric")).findFirst().orElseThrow()); + JsonObject result = new JsonObject(); + for (var dependency : info.getDependencies()) { + JsonObject entry = new JsonObject(); + entry.addProperty("mandatory", dependency.isMandatory()); + entry.addProperty("versionRange", dependency.getVersionRange().toString()); + entry.addProperty("ordering", dependency.getOrdering().name()); + entry.addProperty("side", dependency.getSide().name()); + if (result.has(dependency.getModId())) throw new AssertionError("Duplicate native dependency"); + result.add(dependency.getModId(), entry); + } + return result; + } +} diff --git a/src/test/java/zone/moddev/mc/baseelectric/verification/NativeTestBootstrap.java b/src/test/java/zone/moddev/mc/baseelectric/verification/NativeTestBootstrap.java index 40dfe507..c3d41071 100644 --- a/src/test/java/zone/moddev/mc/baseelectric/verification/NativeTestBootstrap.java +++ b/src/test/java/zone/moddev/mc/baseelectric/verification/NativeTestBootstrap.java @@ -4,8 +4,6 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.List; -import java.util.Optional; -import cpw.mods.modlauncher.api.IModuleLayerManager; import net.minecraft.SharedConstants; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; @@ -13,10 +11,6 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.server.Bootstrap; import net.minecraftforge.common.ForgeMod; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.ModLoader; -import net.minecraftforge.fml.loading.FMLLoader; -import net.minecraftforge.fml.loading.LoadingModList; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistry; @@ -33,44 +27,34 @@ private NativeTestBootstrap() {} public static synchronized void initialize() { if (ready) return; SharedConstants.tryDetectVersion(); - initializeEmptyModList(); Bootstrap.bootStrap(); // The plain test JVM has no FML registration phase after vanilla bootstrap. GameData.unfreezeData(); ready = true; } - private static void initializeEmptyModList() { - if (FMLLoader.getLoadingModList() != null) return; - try { - // Item components post native FML events even in a worldless JVM. - Field discovered = FMLLoader.class.getDeclaredField("loadingModList"); - discovered.setAccessible(true); - LoadingModList loading = LoadingModList.of(List.of(), List.of(), null); - loading.setBrokenFiles(List.of()); - discovered.set(null, loading); - Field layers = FMLLoader.class.getDeclaredField("moduleLayerManager"); - layers.setAccessible(true); - layers.set(null, (IModuleLayerManager) ignored -> Optional.of(ModuleLayer.boot())); - ModList mods = ModList.of(List.of(), List.of()); - Method load = ModList.class.getDeclaredMethod("setLoadedMods", List.class); - load.setAccessible(true); - load.invoke(mods, List.of()); - Field valid = ModLoader.class.getDeclaredField("loadingStateValid"); - valid.setAccessible(true); - valid.setBoolean(ModLoader.get(), true); - } catch (ReflectiveOperationException failure) { - throw new IllegalStateException("Cannot prepare the Forge 52 worldless test context", failure); - } - } - public static RegistryAccess.Frozen registries() { return RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY); } + public static net.minecraft.world.level.storage.ValueInput input(net.minecraft.nbt.CompoundTag data) { + return net.minecraft.world.level.storage.TagValueInput.create(net.minecraft.util.ProblemReporter.DISCARDING, + registries(), data); + } + public static synchronized void registerVanillaFluidTypes() throws ReflectiveOperationException { + registerNativeForgeRegistry(ForgeRegistries.FLUID_TYPES, "VANILLA_FLUID_TYPES"); + } + + public static synchronized void registerVanillaIngredientSerializers() throws ReflectiveOperationException { + registerNativeForgeRegistry(ForgeRegistries.INGREDIENT_SERIALIZERS, "INGREDIENT_SERIALIZERS"); + } + + private static void registerNativeForgeRegistry(DeferredRegister.RegistryHolder registry, String contentsField) + throws ReflectiveOperationException { initialize(); - if (ForgeRegistries.FLUID_TYPES.get() != null) return; + if (registry.get() != null) return; + ResourceKey key = registry.getKey(); // Run the same narrow Forge registry phases as Power's worldless entity fixtures. NewRegistryEvent event = new NewRegistryEvent(); @@ -78,7 +62,7 @@ public static synchronized void registerVanillaFluidTypes() throws ReflectiveOpe registries.setAccessible(true); var deferred = ((List) registries.get(null)).stream() .map(candidate -> (DeferredRegister) candidate) - .filter(candidate -> candidate.getRegistryKey().equals(ForgeRegistries.Keys.FLUID_TYPES)) + .filter(candidate -> candidate.getRegistryKey().equals(key)) .findFirst().orElseThrow(); // Dispatch the two native events directly; plain JUnit has no EventBus bytecode transform. Class dispatcher = Class.forName(DeferredRegister.class.getName() + "$EventDispatcher"); @@ -94,11 +78,11 @@ public static synchronized void registerVanillaFluidTypes() throws ReflectiveOpe Constructor registerEvent = RegisterEvent.class.getDeclaredConstructor( ResourceKey.class, ForgeRegistry.class, Registry.class); registerEvent.setAccessible(true); - Field vanilla = ForgeMod.class.getDeclaredField("VANILLA_FLUID_TYPES"); + Field vanilla = ForgeMod.class.getDeclaredField(contentsField); vanilla.setAccessible(true); Method handle = dispatcher.getDeclaredMethod("handleEvent", RegisterEvent.class); handle.setAccessible(true); handle.invoke(listener.newInstance(vanilla.get(null)), registerEvent.newInstance( - ForgeRegistries.Keys.FLUID_TYPES, ForgeRegistries.FLUID_TYPES.get(), null)); + key, registry.get(), null)); } } diff --git a/tools/generate-recipe-unlocks.js b/tools/generate-recipe-unlocks.js index 86642ddf..eae57386 100644 --- a/tools/generate-recipe-unlocks.js +++ b/tools/generate-recipe-unlocks.js @@ -14,6 +14,7 @@ const ignored = new Set(['item:minecraft:stick', 'item:minecraft:string', function choices(value) { if (Array.isArray(value)) return value.flatMap(choices); + if (typeof value === 'string') return value.startsWith('#') ? [{tag: value.slice(1)}] : [{item: value}]; if (value && value.tag) return [{tag: value.tag}]; if (value && value.item) return [{item: value.item}]; throw new Error('Unsupported recipe ingredient: ' + JSON.stringify(value)); diff --git a/tools/verification/AuditedJUnit.java b/tools/verification/AuditedJUnit.java index 4b279a7e..fa80d4e1 100644 --- a/tools/verification/AuditedJUnit.java +++ b/tools/verification/AuditedJUnit.java @@ -30,7 +30,7 @@ public static void main(String[] args) throws Exception { XMLStreamWriter xml = XMLOutputFactory.newFactory().createXMLStreamWriter(output, "UTF-8"); xml.writeStartDocument("UTF-8", "1.0"); xml.writeStartElement("testsuite"); - xml.writeAttribute("name", "baseElectric-1.18.2-ECJ"); + xml.writeAttribute("name", "baseElectric-1.21.11-ECJ"); xml.writeAttribute("tests", Integer.toString(result.getRunCount())); xml.writeAttribute("failures", Integer.toString(result.getFailureCount())); xml.writeAttribute("ignored", Integer.toString(result.getIgnoreCount())); diff --git a/tools/verification/Invoke-ElectricPackagedSmoke.ps1 b/tools/verification/Invoke-ElectricPackagedSmoke.ps1 index 12e14879..11ec3cf7 100644 --- a/tools/verification/Invoke-ElectricPackagedSmoke.ps1 +++ b/tools/verification/Invoke-ElectricPackagedSmoke.ps1 @@ -30,7 +30,7 @@ $target = "$($pins.minecraft_version)-$($pins.forge_version)" $forgeDir = "libraries/net/minecraftforge/forge/$target" $winArgs = "$forgeDir/win_args.txt" $receipt = [ordered]@{ - status = 'FAIL'; scope = 'Packaged Forge 1.21.1 dedicated server and legacy inventory probe; no client or whole-world upgrade proof' + status = 'FAIL'; scope = 'Packaged Forge 1.21.11 dedicated server and legacy inventory probe; no client or whole-world upgrade proof' baseMetalsIncluded = !$WithoutBaseMetals seed = $seed; java = $javaPath; inputs = @(); checks = [ordered]@{}; exitCode = $null; error = $null } @@ -63,8 +63,8 @@ function Send-Command([string]$Command) { } try { - if ($target -cne '1.21.1-52.1.0' -or $pins.mod_version -cne '2.2.15.121011') { - throw 'This smoke runner is bound to baseElectric 2.2.15.121011 on Forge 52.1.0.' + if ($target -cne '1.21.11-61.1.0' -or $pins.mod_version -cne '2.2.16.121111') { + throw 'This smoke runner is bound to baseElectric 2.2.16.121111 on Forge 61.1.0.' } if ($pins.poweradvantage_pin_state -notin @('LOCAL_SOURCE', 'MERGED_SOURCE') -or $PowerSha256 -ne $pins.poweradvantage_runtime_sha256) { throw 'Packaged smoke requires the exact source-pinned basePower player JAR.' @@ -78,11 +78,16 @@ try { $receipt.javaSha256 = (Get-FileHash -LiteralPath $javaPath).Hash $argsText = Get-Content -LiteralPath (Join-Path $seed $winArgs) -Raw $shim = "forge-$target-shim.jar" - if (!$argsText.Contains("-jar $shim")) { throw 'Unexpected Forge 52 server argument file.' } + if (!$argsText.Contains("-jar $shim")) { throw 'Unexpected Forge 61 server argument file.' } $receipt.shimSha256 = (Get-FileHash -LiteralPath (Join-Path $seed $shim)).Hash + if ($receipt.shimSha256 -cne $pins.forge_shim_sha256) { throw 'Forge shim differs from the recorded 61.1.0 runtime pin.' } $receipt.seedArgumentsSha256 = (Get-FileHash -LiteralPath (Join-Path $seed $winArgs)).Hash $forgeUniversal = Join-Path $seed "$forgeDir/forge-$target-universal.jar" $receipt.forgeUniversalSha256 = (Get-FileHash -LiteralPath $forgeUniversal).Hash + if ($receipt.forgeUniversalSha256 -cne $pins.forge_universal_sha256) { throw 'Forge universal differs from the recorded 61.1.0 runtime pin.' } + $forgeServer = Join-Path $seed "$forgeDir/forge-$target-server.jar" + $receipt.forgeServerSha256 = (Get-FileHash -LiteralPath $forgeServer).Hash + if ($receipt.forgeServerSha256 -cne $pins.forge_server_sha256) { throw 'Forge server differs from the recorded 61.1.0 runtime pin.' } if ((Get-Content -LiteralPath $EulaFile -Raw) -notmatch '(?m)^eula=true\s*$') { throw 'Pass the existing accepted EULA from the local smoke fixture.' } diff --git a/tools/verification/Verify-ElectricEcj.ps1 b/tools/verification/Verify-ElectricEcj.ps1 index edc03009..ac7be307 100644 --- a/tools/verification/Verify-ElectricEcj.ps1 +++ b/tools/verification/Verify-ElectricEcj.ps1 @@ -61,16 +61,16 @@ function Invoke-Ecj([string]$Name, [string[]]$Sources, [string[]]$Libraries) { } $report = [ordered]@{ status = 'RUNNING'; project = $ProjectRoot; evidence = $Evidence - scope = 'Pinned local baseElectric 1.21.1 candidate; fresh ECJ main/test/helper outputs and worldless Java 21 JUnit; no Gradle or Minecraft launch' + scope = 'Pinned local baseElectric 1.21.11 candidate; fresh ECJ main/test/helper outputs and worldless Java 21 JUnit; no Gradle or Minecraft launch' compiler = $null; toolchains = $null; libraries = @(); sources = @(); gradleInventory = @() compilations = [ordered]@{}; junit = $null; negativeControl = $null; apiPinState = $null } try { $properties = ConvertFrom-StringData -StringData (Get-Content -LiteralPath (Join-Path $ProjectRoot 'gradle.properties') -Raw) $report.apiPinState = $properties.poweradvantage_pin_state - if ($properties.mod_id -ne 'baseelectric' -or $properties.mod_version -ne '2.2.15.121011' -or - $properties.minecraft_version -ne '1.21.1' -or $properties.forge_version -ne '52.1.0' -or - $properties.poweradvantage_version -ne '2.4.14.121011' -or $properties.basemetals_version -ne '3.1.2.121011' -or - $properties.orespawn_version -ne '4.1.0.121011' -or + if ($properties.mod_id -ne 'baseelectric' -or $properties.mod_version -ne '2.2.16.121111' -or + $properties.minecraft_version -ne '1.21.11' -or $properties.forge_version -ne '61.1.0' -or + $properties.poweradvantage_version -ne '2.4.15.121111' -or $properties.basemetals_version -ne '3.1.2.121111' -or + $properties.orespawn_version -ne '4.1.0.121111' -or $properties.poweradvantage_pin_state -notin @('LOCAL_SOURCE', 'MERGED_SOURCE') -or $properties.poweradvantage_source_ref -cnotmatch '^[a-f0-9]{40}$' -or $properties.poweradvantage_runtime_sha256 -cnotmatch '^[A-F0-9]{64}$' -or @@ -78,7 +78,7 @@ try { $properties.poweradvantage_deobf_sha256 -cnotmatch '^[A-F0-9]{64}$' -or $properties.basemetals_deobf_sha256 -cnotmatch '^[A-F0-9]{64}$' -or $properties.orespawn_deobf_sha256 -cnotmatch '^[A-F0-9]{64}$') { - throw 'This verifier requires the source-pinned baseElectric 1.21.1 inputs' + throw 'This verifier requires the source-pinned baseElectric 1.21.11 inputs' } $report.compiler = Get-Pin $Compiler if ($report.compiler.sha256 -ne 'D0D43F8E2D7003E5EFED612E2CBB5F01870043397D8F1BBE536FD9128F4FCBF7') { throw 'ECJ compiler pin mismatch' } @@ -137,7 +137,7 @@ try { $expected += [int]$inventory.testsuite.tests $report.gradleInventory += Get-Pin $xml.FullName } - if ($classes.Count -ne 31 -or $expected -ne 106 -or $sources.test.Count -ne 33 -or $sources.main.Count -ne 86) { throw 'Unexpected Electric 1.21.1 source/test inventory' } + if ($classes.Count -ne 33 -or $expected -ne 114 -or $sources.test.Count -ne 36 -or $sources.main.Count -ne 88) { throw 'Unexpected Electric 1.21.11 source/test inventory' } $main = Invoke-Ecj 'main' $sources.main $mainLibraries $test = Invoke-Ecj 'test' $sources.test (@($main) + $testLibraries) $gameTests = @(Get-ChildItem -LiteralPath (Join-Path $ProjectRoot 'src/gametest/java') -Recurse -File -Filter '*.java' | ForEach-Object { $_.FullName }) diff --git a/tools/verify-native-port.js b/tools/verify-native-port.js index c40bf0b9..fb49ac0a 100644 --- a/tools/verify-native-port.js +++ b/tools/verify-native-port.js @@ -5,7 +5,7 @@ const { execFileSync } = require('node:child_process'); const { createHash } = require('node:crypto'); const root = path.resolve(__dirname, '..'); -const baseline = '8160dba30c5146ff50b8ce0c314085f965fb2964'; +const baseline = 'b81645579c3330476b84149402c3ce78183df85f'; const legacyTrackBaseline = '013737d4cc41947e8b6fa42f4bf926a1fa5ab998'; const git = (...args) => execFileSync('git', args, { cwd: root }); const old = file => git('show', baseline + ':' + file); @@ -20,9 +20,14 @@ const relocated = file => file.replace(/(data\/[^/]+\/)recipes\//, '$1recipe/') .replace(/(data\/[^/]+\/)loot_tables\//, '$1loot_table/') .replace(/(data\/[^/]+\/tags\/)items\//, '$1item/') .replace(/(data\/[^/]+\/tags\/)blocks\//, '$1block/'); -const nativeLocations = source => source.toString() - .replace(/new ResourceLocation\(\s*([\w.]+|"[^"]+"),/g, 'ResourceLocation.fromNamespaceAndPath($1,') - .replaceAll('new ResourceLocation(', 'ResourceLocation.parse('); +function nativeIngredients(recipe) { + const ingredient = value => Array.isArray(value) ? value.map(ingredient) + : typeof value === 'string' ? value : value.item || '#' + value.tag; + if (recipe.key) recipe.key = Object.fromEntries(Object.entries(recipe.key).map(([key, value]) => [key, ingredient(value)])); + if (recipe.ingredient) recipe.ingredient = ingredient(recipe.ingredient); + if (recipe.ingredients) recipe.ingredients = ingredient(recipe.ingredients); + return recipe; +} const track = file => file.startsWith(assets + 'models/block/electric_track_') && file.endsWith('.json'); const checks = []; function check(name, run) { @@ -30,24 +35,39 @@ function check(name, run) { catch (error) { checks.push({name, pass: false, error: error.message}); } } -check('Exact Forge 52 and local port identity', () => { +check('Exact Forge 61 and local port identity', () => { const props = Object.fromEntries(read('gradle.properties').toString().split(/\r?\n/) .filter(line => /^[a-z][a-z_\d]*=/.test(line)).map(line => line.split(/=(.*)/s).slice(0, 2))); for (const [key, value] of Object.entries({ - minecraft_version: '1.21.1', forge_version: '52.1.0', mapping_channel: 'official', - mapping_version: '1.21.1', mcp_version: '20240808.132146', java_version: '21', - mod_id: 'baseelectric', mod_name: 'baseElectric', mod_version: '2.2.15.121011', - poweradvantage_version: '2.4.14.121011', basemetals_version: '3.1.2.121011', - basemetals_source_commit: 'b42b92b0e6f60ac5baf07a6b74042b2fa8427904', - basemetals_deobf_sha256: '7C0B961A8D4991C9B69379518AAD700A71C1E4B2076CF5DEF292C58029408A07', - orespawn_source_commit: '62c08169c71f4d4fd8f107289e63fd2a4c7c655c', - orespawn_version: '4.1.0.121011', curseforge_project_id: '1783006', + minecraft_version: '1.21.11', forge_version: '61.1.0', mapping_channel: 'official', + mapping_version: '1.21.11', mcp_version: '20251223.124241', java_version: '21', + mod_id: 'baseelectric', mod_name: 'baseElectric', mod_version: '2.2.16.121111', + poweradvantage_version: '2.4.15.121111', basemetals_version: '3.1.2.121111', + poweradvantage_pin_state: 'MERGED_SOURCE', + poweradvantage_source_ref: '9b0043483d79d3e575895f12aeb0dde7ef6c4890', + poweradvantage_public_file_id: '9566998', + poweradvantage_deobf_sha256: 'C98D2CF163BE2480D9AFB0023BBD2D92D401AE0D50BEF73191235BF3F83774A7', + poweradvantage_runtime_sha256: 'C98D2CF163BE2480D9AFB0023BBD2D92D401AE0D50BEF73191235BF3F83774A7', + basemetals_source_commit: '6f4c44e4d0a68bca3838fb025c09cddfaaa08fe8', + basemetals_public_file_id: '9566738', + basemetals_deobf_sha256: '598D3FB0FF956EBCC67FE477A01CE393C75D0013AF0CE00A79E2072B63E9F2BA', + basemetals_runtime_sha256: '598D3FB0FF956EBCC67FE477A01CE393C75D0013AF0CE00A79E2072B63E9F2BA', + orespawn_source_commit: 'ecad75b24309a344f712d898d717c6a8823fc9f2', + orespawn_deobf_sha256: 'DE39929057288CEA110196C9E9D708E129B80BC360A2E53976337FFA6A84A67B', + orespawn_version: '4.1.0.121111', curseforge_project_id: '1783006', cf_requirements: 'basepower,base-metals' })) assert.equal(props[key], value, key); - assert.deepEqual(json('src/main/resources/pack.mcmeta').pack, {pack_format:34, supported_formats:{min_inclusive:34,max_inclusive:48}, description:'baseElectric'}); + assert.deepEqual(json('src/main/resources/pack.mcmeta').pack, + {min_format:[94,1], max_format:[94,1], description:'baseElectric'}); const mods = read('src/main/resources/META-INF/mods.toml').toString(); - assert.match(mods, /modId="basepower"\s+mandatory=true\s+versionRange="\[2\.4\.14\.121011,3\.0\.0\)"/); - assert.match(mods, /modId="basemetals"\s+mandatory=false\s+versionRange="\[3\.1\.2\.121011,4\.0\.0\)"/); + assert.match(mods, /^showAsResourcePack=false$/m); + assert.match(mods, /modId="basepower"\s+mandatory=true\s+versionRange="\[2\.4\.15\.121111,3\.0\.0\)"/); + assert.match(mods, /modId="basemetals"\s+mandatory=true\s+versionRange="\[3\.1\.2\.121111,4\.0\.0\)"/); + const build = read('build.gradle').toString(); + assert.match(build, /inputs\.files\(javadocTool\.map/); + assert.match(build, /legal\/java\.base/); + assert.match(build, /filesMatching\('\*\*\/\*\.svg', normalizeArchiveLineEndings\)/); + assert.match(build, /must contain the selected JDK's full canonical legal text/); }); function checkTrackModel(file, model) { @@ -76,20 +96,35 @@ check('Track audit rejects the old asset and a geometry mutation', () => { assert.throws(() => checkTrackModel(file, mutated), /changed beyond the render layer/); }); -check('Shipped resources and fixtures retain released 1.20.6 bytes under singular registry folders', () => { +check('Accepted 1.21.1 resources retain bytes except native recipe schema and pack metadata', () => { const resources = tracked.filter(file => /^src\/(main|test)\/resources\//.test(file)); const exceptions = new Set(['src/main/resources/pack.mcmeta', 'src/main/resources/META-INF/mods.toml']); for (const file of resources.filter(file => !exceptions.has(file))) { + if (file.startsWith('src/main/resources/data/baseelectric/recipe/')) { + assert.deepEqual(json(file), nativeIngredients(JSON.parse(old(file))), file); + continue; + } assert.equal(sha256(read(relocated(file))), sha256(old(file)), file); if (relocated(file) !== file) assert(!fs.existsSync(path.join(root, file)), 'Obsolete registry path: ' + file); } const actual = fs.readdirSync(path.join(root, 'src'), {recursive:true, withFileTypes:true}) .filter(entry => entry.isFile()).map(entry => path.relative(root, path.join(entry.parentPath, entry.name)) .split(path.sep).join('/')).sort(); - assert.deepEqual(actual, [...tracked.map(relocated), - javaRoot.replace('main', 'test') + 'resources/DatapackLayoutTest.java', - javaRoot.replace('main', 'test') + 'verification/NativeMachineFixture.java', - javaRoot.replace('main', 'test') + 'verification/NativeMachineFixtureTest.java'].sort(), + const definitions = tracked.filter(file => file.startsWith(assets + 'models/item/') && file.endsWith('.json')) + .map(file => file.replace('/models/item/', '/items/')); + assert.equal(definitions.length, 44); + for (const file of definitions) { + const id = path.basename(file, '.json'); + assert.deepEqual(json(file), {model:{type:'minecraft:model', model:'baseelectric:item/' + id}}, file); + } + assert.deepEqual(actual, [...tracked.map(relocated), ...definitions, + javaRoot + 'util/RegistryIds.java', javaRoot + 'util/LegacyNbt.java', + javaRoot.replace('main', 'test') + 'util/crafting/RecipeDeconstructorTest.java', + javaRoot.replace('main', 'test') + 'resources/NativePackRangeContractTest.java', + javaRoot.replace('main', 'test') + 'verification/NativePackResourceProof.java', + ...['drillupgradesandtransferslegacybattery', 'recipeavailabilitydoesnotremovediscovery', + 'siliconandsolderresolverealmaterialtags', 'turretusesnativeupdatepacket'] + .map(name => 'src/gametest/resources/data/baseelectric/test_instance/' + name + '.json')].sort(), 'Source and resource inventory'); }); @@ -99,11 +134,16 @@ check('Migration and registration code keep their accepted IDs and compatibility 'init/Entities.java', 'init/GUI.java', 'init/OreSpawnWorldGen.java' ]) { const file = javaRoot + name; - assert.equal(read(file).toString().replace(/\s/g, ''), nativeLocations(old(file)).replace(/\s/g, ''), file); + const strings = source => new Set(source.toString().match(/"(?:\\.|[^"\\])*"/g)); + const current = strings(read(file)); + for (const id of strings(old(file))) assert(current.has(id), file + ' lost ' + id); } + const migration = javaRoot + 'migration/ElectricLegacyMigrations.java'; + assert.equal(read(migration).toString().replace(/\s/g,''), old(migration).toString() + .replaceAll('ResourceLocation', 'Identifier').replace(/\s/g,'')); }); -check('All 102 released tests and their semantic assertions are retained', () => { +check('All 106 accepted tests and their assertions are retained without skips', () => { const methods = value => [...value.toString().matchAll(/@Test\s+public void (\w+)\(/g)].map(m => m[1]); const files = tracked.filter(file => file.startsWith('src/test/java/') && file.endsWith('.java')); let inherited = 0; @@ -119,8 +159,14 @@ check('All 102 released tests and their semantic assertions are retained', () => inherited += priorMethods.length; actual += currentMethods.length; } - assert.equal(inherited, 102); - assert.equal(actual, 102); + assert.equal(inherited, 106); + assert.equal(actual, 106); + const added = read(javaRoot.replace('main','test') + 'util/crafting/RecipeDeconstructorTest.java'); + assert.equal(methods(added).length, 2); + assert.doesNotMatch(added.toString(), /@Ignore|Assume\.|assumeTrue\(|assumeFalse\(/); + const pack = read(javaRoot.replace('main', 'test') + 'resources/NativePackRangeContractTest.java'); + assert.equal(methods(pack).length, 6); + assert.doesNotMatch(pack.toString(), /@Ignore|Assume\.|assumeTrue\(|assumeFalse\(/); const gameTests = javaRoot.replace('main', 'gametest') + 'gametest/ElectricGameTests.java'; const names = value => [...value.toString().matchAll(/public static void (\w+)\(GameTestHelper/g)].map(m => m[1]); for (const name of names(old(gameTests))) assert(names(read(gameTests)).includes(name), 'Lost GameTest: ' + name); @@ -128,10 +174,10 @@ check('All 102 released tests and their semantic assertions are retained', () => check('All 58 recipe IDs, results, guards and ingredients are unchanged', () => { - const files = tracked.filter(file => /\/data\/baseelectric\/recipes\/.*\.json$/.test(file)); + const files = tracked.filter(file => /\/data\/baseelectric\/recipe\/.*\.json$/.test(file)); assert.equal(files.length, 58); for (const file of files) { - const expected = JSON.parse(old(file)); + const expected = nativeIngredients(JSON.parse(old(file))); assert.deepEqual(json(relocated(file)), expected, file); } });