From 337ebcce39f650ef2308da35def4dab6af0a390e Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Sat, 19 Sep 2026 17:02:22 +0100 Subject: [PATCH 1/2] Port Sky's Grass Slabs to Minecraft 26.3 --- .github/workflows/ci.yml | 18 ++-- .github/workflows/codeql-analysis.yml | 4 +- .github/workflows/validate-gradle-build.yml | 4 +- CHANGELOG.md | 7 ++ README.md | 6 +- build.gradle | 48 +++++----- ci-fixtures/tools/README.md | 6 +- ...craft-mavenizer-0.5.21-orespawn-compat.jar | Bin 2566958 -> 2566958 bytes ...aft-mavenizer-0.5.21-orespawn-compat.patch | 13 +-- .../tools/minecraft-source-compatibility.json | 2 +- docs/RELEASE-1.1.2.2603001.md | 12 +++ docs/WORLD-UPGRADES.md | 6 +- gradle.properties | 14 +-- gradle/wrapper/gradle-wrapper.properties | 4 +- .../gametest/SlabGameTests.java | 80 +++++++++------- .../gametest/WorldgenGameTests.java | 41 ++++---- .../mc/skysgrassslabs/SkysGrassSlabs.java | 2 +- .../skysgrassslabs/block/DirtSlabBlock.java | 8 -- .../skysgrassslabs/block/GrassSlabBlock.java | 31 +++--- .../skysgrassslabs/block/SlabFlattening.java | 65 +++++++++++++ .../skysgrassslabs/block/SlabTransitions.java | 6 +- .../skysgrassslabs/block/TurfBlockItem.java | 2 +- .../mc/skysgrassslabs/event/CommonEvents.java | 9 +- .../mc/skysgrassslabs/init/ModBlocks.java | 6 +- .../item/NormalizingSlabItem.java | 2 +- .../mc/skysgrassslabs/item/ShovelSupport.java | 18 ++++ .../recipe/TurfCuttingRecipe.java | 8 +- .../world/GrassSlabSmoothingFeature.java | 21 +++-- .../skysgrassslabs/world/ModWorldState.java | 4 +- .../world/SmoothingBiomeModifier.java | 2 +- .../world/WorldgenBootstrap.java | 20 ++-- .../advancement/recipes/dirt_slab.json | 2 +- .../recipes/grass_block_from_seeds.json | 2 +- .../advancement/recipes/grass_slab.json | 2 +- .../recipes/grass_slab_from_seeds.json | 2 +- .../advancement/recipes/turf.json | 2 +- .../loot_table/blocks/dirt_slab.json | 43 +++++---- .../loot_table/blocks/grass_slab.json | 88 +++++++++--------- .../loot_table/blocks/path_slab.json | 43 +++++---- .../loot_table/blocks/turf.json | 9 +- src/main/resources/pack.mcmeta | 7 +- .../ForwardUpgradeFixtureContractTest.java | 4 + .../skysgrassslabs/ProjectContractTest.java | 34 +++---- .../skysgrassslabs/ResourceContractTest.java | 6 +- ...skysgrassslabs-26.2-forward-world.manifest | 8 ++ .../skysgrassslabs-26.2-forward-world.zip | Bin 0 -> 95080 bytes .../installed-grassslabs/META-INF/mods.toml | 10 +- .../installed-grassslabs/pack.mcmeta | 4 +- .../resources/META-INF/mods.toml | 6 +- .../resources/pack.mcmeta | 4 +- 50 files changed, 431 insertions(+), 314 deletions(-) create mode 100644 docs/RELEASE-1.1.2.2603001.md create mode 100644 src/main/java/zone/moddev/mc/skysgrassslabs/block/SlabFlattening.java create mode 100644 src/main/java/zone/moddev/mc/skysgrassslabs/item/ShovelSupport.java create mode 100644 src/test/resources/fixtures/skysgrassslabs-26.2-forward-world.manifest create mode 100644 src/test/resources/fixtures/skysgrassslabs-26.2-forward-world.zip diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 858387a..5f04f21 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,18 +1,18 @@ -name: Sky's Grass Slabs 26.2 CI +name: Sky's Grass Slabs 26.3 CI on: push: branches: - - master-26.2 + - master-26.3 pull_request: branches: - - master-26.2 + - master-26.3 permissions: contents: read concurrency: - group: skysgrassslabs-26.2-${{ github.workflow }}-${{ github.ref }} + group: skysgrassslabs-26.3-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: @@ -107,13 +107,13 @@ jobs: - name: Upload audited release candidate uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: SkysGrassSlabs-26.2-${{ github.sha }} + name: SkysGrassSlabs-26.3-${{ github.sha }} if-no-files-found: error retention-days: 30 path: | - build/libs/SkysGrassSlabs-1.1.2.2602001.jar - build/libs/SkysGrassSlabs-1.1.2.2602001-sources.jar - build/libs/SkysGrassSlabs-1.1.2.2602001-javadoc.jar + build/libs/SkysGrassSlabs-1.1.2.2603001.jar + build/libs/SkysGrassSlabs-1.1.2.2603001-sources.jar + build/libs/SkysGrassSlabs-1.1.2.2603001-javadoc.jar build/release/SHA256SUMS CHANGELOG.md @@ -121,7 +121,7 @@ jobs: if: failure() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: SkysGrassSlabs-26.2-diagnostics-${{ github.sha }} + name: SkysGrassSlabs-26.3-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 cd6cb76..ac5a322 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -3,10 +3,10 @@ name: CodeQL on: push: branches: - - master-26.2 + - master-26.3 pull_request: branches: - - master-26.2 + - master-26.3 schedule: - cron: '53 7 * * 4' diff --git a/.github/workflows/validate-gradle-build.yml b/.github/workflows/validate-gradle-build.yml index eff97dd..98e3115 100644 --- a/.github/workflows/validate-gradle-build.yml +++ b/.github/workflows/validate-gradle-build.yml @@ -3,10 +3,10 @@ name: Validate Gradle Wrapper on: push: branches: - - master-26.2 + - master-26.3 pull_request: branches: - - master-26.2 + - master-26.3 permissions: contents: read diff --git a/CHANGELOG.md b/CHANGELOG.md index 20ff579..2b9829c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 1.1.2.2603001 - Minecraft 26.3 + +- Ported the complete feature set to Minecraft 26.3 and Forge 66. +- Preserved all blocks, recipes, settings and supported world upgrades. +- Updated shovel handling, bonemeal growth, world generation and data files + for Minecraft 26.3. + ## 1.1.2.2602001 - Minecraft 26.2 - Corrected snowy grass slabs so their exposed top uses the snow texture diff --git a/README.md b/README.md index e8475dc..1bbbc82 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ thin layer of turf. Grass spreads naturally between full blocks and slabs, while new Overworld terrain uses grass slabs to soften suitable one block steps. -This branch is for Minecraft 26.2. Version `1.1.2.2602001` requires Forge -65.1.0 or a compatible Forge 65 build and Java 25. +This branch is for Minecraft 26.3. Version `1.1.2.2603001` requires Forge +66.0.0 or a compatible Forge 66 build and Java 25. ## Installation @@ -34,7 +34,7 @@ or updating world changing mods. - [Gameplay and recipes](docs/GAMEPLAY.md) - [Configuration](docs/CONFIGURATION.md) - [Upgrading an older world](docs/WORLD-UPGRADES.md) -- [Release notes](docs/RELEASE-1.1.2.2602001.md) +- [Release notes](docs/RELEASE-1.1.2.2603001.md) ## License diff --git a/build.gradle b/build.gradle index 09c9655..3ce60a4 100644 --- a/build.gradle +++ b/build.gradle @@ -37,15 +37,15 @@ def mavenizerLicense = mavenizerToolsDirectory.file('LICENSE-MAVENIZER.txt') def mavenizerReadme = mavenizerToolsDirectory.file('README.md') def mavenizerFixtureChecksums = [ (mavenizerCompatibilityJar.asFile): - '5ABAB52A3F1BE115381C3CE80D5FD38DBE6C9F4C0B9ECF70A957700EC90FB88B', + '4150926F33A696B2088AB2675C1C3B45745CE4F9F2DEB31CCD88C9ADC834062F', (mavenizerRuleManifest.asFile): - '9437E03FC5E1CB5D605D72F0538C4DF4417B64DB0A57D0AABDC5184781517AC1', + '829400D74ECB1BF0CC6107D9980B8328365E3F56D9A5342002D8DF340571BDB7', (mavenizerSourcePatch.asFile): - '2DA8DD0FD5F112F5B7591113AED06D9A58C584A25F8705E26445A6D2E9D5C78E', + '9F0C34529D41C9CD5804C32608FE548D09A0AC3A95D337EE2EF4377680C1B2DD', (mavenizerLicense.asFile): '20C17D8B8C48A600800DFD14F95D5CB9FF47066A9641DDEAB48DC54AEC96E331', (mavenizerReadme.asFile): - 'EAD1477F393897C491A10FB86178213A99C360571A8063D551DA0579DF65BA6F' + 'A35B80BA8D7557A31E0378787C06FE86C8C627061BF313A6886205F62A46C09F' ] // ForgeGradle invokes Mavenizer while configuring the project. Verify the @@ -87,7 +87,7 @@ java { withJavadocJar() } -// ForgeGradle declares Slime Launcher as Java 8-compatible, but Forge 65 and +// ForgeGradle declares Slime Launcher as Java 8-compatible, but Forge 66 and // this project run entirely on Java 25. Bind the launcher explicitly so a // clean setup does not depend on an unrelated legacy JDK. fgtools.configure('slimelauncher') { @@ -261,7 +261,7 @@ tasks.named('check').configure { // A Forge process is not green merely because it returns exit code zero. The // loader can log a worldgen or linkage failure and still shut down normally. -def acceptedForge65LogNoise = [ +def acceptedForge66LogNoise = [ ~/FML appears to be missing any signature data/, ~/Found multiple arguments for option fml\.mcVersion/, ~/Found multiple arguments for option fml\.forgeVersion/, @@ -281,7 +281,7 @@ def packagedOfflineAuthenticationNoise = [ ~/\/ERROR\] \[com\.mojang\.realmsclient\.RealmsAvailability\/\]: Couldn't connect to realms$/, ~/^com\.mojang\.realmsclient\.exception\.RealmsServiceException: Realms authentication error with message 'java\.lang\.RuntimeException: Failed to parse into SignedJWT: validation-token'$/ ] -// Forge 65 asks OSHI for Windows performance counters while preloading its +// Forge 66 asks OSHI for Windows performance counters while preloading its // system report. Control Forge runtimes reproduced these exact signatures and // continued to Done. Keep the exception scoped to Windows runs that opt in. def windowsOshiSystemReportNoise = [ @@ -319,7 +319,7 @@ def assertRuntimeLogsClean = { File runDirectory, String context, Set priorCrash log.eachLine('UTF-8') { String line -> lineNumber++ boolean unexpectedSeverity = line ==~ /.*\/(?:ERROR|FATAL)\].*/ - boolean knownNoise = acceptedForge65LogNoise.any { line =~ it } + boolean knownNoise = acceptedForge66LogNoise.any { line =~ it } || contextNoise.any { line =~ it } boolean exceptionRoot = line ==~ /^(?:Caused by: )?[A-Za-z_$][A-Za-z0-9_.$]*(?:Exception|Error)(?::.*)?$/ boolean fatalText = line.contains('Encountered an unexpected exception') || @@ -359,7 +359,7 @@ tasks.register('runtimeLogScannerTest') { 'java.lang.UnsupportedOperationException: sun.misc.Unsafe unavailable\n' + 'java.lang.UnsupportedOperationException: Native access (restricted methods) is not enabled for the io.netty.common module.\n', 'UTF-8') - assertRuntimeLogsClean(probe, 'scanner-forge65-netty-noise-probe', [] as Set) + assertRuntimeLogsClean(probe, 'scanner-forge66-netty-noise-probe', [] as Set) new File(logs, 'debug.log').delete() new File(logs, 'latest.log').setText( '[Download-2/ERROR] [net.minecraft.client.Minecraft/]: Failed to fetch user properties\n' @@ -430,7 +430,7 @@ def processedMainResourcesPath = { project.relativePath(processedMainResourcesDirectory()).replace('\\', '/') } -// ForgeGradle 7 models Forge 65 source sets as merged output directories. +// ForgeGradle 7 models Forge 66 source sets as merged output directories. // Compile through staging so Gradle and Eclipse never write classes and // processed resources to the same location at the same time. def compiledMainClasses = layout.buildDirectory.dir('compiled-classes/main') @@ -529,13 +529,13 @@ repositories { dependencies { implementation minecraft.dependency( "net.minecraftforge:forge:${project.minecraft_version}-${project.forge_version}") - testImplementation 'net.minecraftforge:eventbus-validator:7.0.1' + testImplementation 'net.minecraftforge:eventbus-validator:7.0.6' testImplementation 'junit:junit:4.13.2' } def verifyMavenizerCompatibilityFixture = tasks.register('verifyMavenizerCompatibilityFixture') { group = 'verification' - description = 'Verifies the checksum-sealed Forge 26.2 Mavenizer compatibility fixture.' + description = 'Verifies the checksum-sealed Forge 26.3 Mavenizer compatibility fixture.' inputs.files mavenizerFixtureChecksums.keySet() doLast { mavenizerFixtureChecksums.each { File fixture, String expected -> @@ -550,13 +550,13 @@ def verifyMavenizerCompatibilityFixture = tasks.register('verifyMavenizerCompati } def parsed = new JsonSlurper().parse(mavenizerRuleManifest.asFile) - String target = 'net.minecraftforge:forge:26.2-65.1.0' + String target = 'net.minecraftforge:forge:26.3-66.0.0' if (parsed.schema != 1 || parsed.targets.keySet() != [target] as Set) { throw new GradleException('Mavenizer target-rule manifest has unexpected targets or schema') } def forgeRules = parsed.targets[target] if (forgeRules.expectedApplications != 0 || !forgeRules.rules.isEmpty()) { - throw new GradleException('Forge 65 Mavenizer target must be an explicit zero-rule qualification') + throw new GradleException('Forge 66 Mavenizer target must be an explicit zero-rule qualification') } ZipFile fixtureJar = new ZipFile(mavenizerCompatibilityJar.asFile) @@ -605,7 +605,7 @@ def verifyMavenizerCompatibilityFixture = tasks.register('verifyMavenizerCompati String licenseText = mavenizerLicense.asFile.getText('UTF-8') if (!readme.contains('6968241ce7a0a902cdc1c534b976e8373a423091') || !readme.contains('Temurin `25.0.3+9`') - || !readme.contains('26.2-65.1.0')) { + || !readme.contains('26.3-66.0.0')) { throw new GradleException('Mavenizer provenance, target, or Java 25 build instructions are incomplete') } if (!patchText.contains('SourceCompatibilityPatcher.java') @@ -686,12 +686,12 @@ def releaseFiles = provider { tasks.register('verifyReleaseMetadata') { group = 'verification' doLast { - if (project.minecraft_version != '26.2' || project.forge_version != '65.1.0' || - project.mapping_channel != 'official' || project.mapping_version != '26.2' || + if (project.minecraft_version != '26.3' || project.forge_version != '66.0.0' || + project.mapping_channel != 'official' || project.mapping_version != '26.3' || project.loader_name != 'forge' || project.loader_code != '1' || project.java_version != '25' || project.java_toolchain_version != '25.0.3+9' || project.gradle_java_version != '25' || project.curseforge_project_id != '1677588') { - throw new GradleException('Unexpected 26.2 release metadata') + throw new GradleException('Unexpected 26.3 release metadata') } } } @@ -769,8 +769,8 @@ tasks.register('verifyReleaseArtifacts') { String metadata = zip.getInputStream(zip.getEntry('META-INF/mods.toml')) .getText(StandardCharsets.UTF_8.name()) - if (!metadata.contains('versionRange="[26.2,26.3,)"') || - !metadata.contains('versionRange="[65,)"')) { + if (!metadata.contains('versionRange="[26.3,26.4,)"') || + !metadata.contains('versionRange="[66,)"')) { throw new GradleException('Packaged Forge metadata targets the wrong version') } @@ -987,9 +987,9 @@ eclipse { synchronizationTasks 'isolateEclipseProductionRuns' } -def syncForge65EclipseLaunches = tasks.register('syncForge65EclipseLaunches') { +def syncForge66EclipseLaunches = tasks.register('syncForge66EclipseLaunches') { group = 'ide' - description = 'Normalizes ForgeGradle 7 Eclipse launch outputs for Forge 65.' + description = 'Normalizes ForgeGradle 7 Eclipse launch outputs for Forge 66.' doLast { String mainOutput = new File(projectDir, 'bin/main').absolutePath String gameTestOutput = new File(projectDir, 'bin/gameTest').absolutePath @@ -1059,14 +1059,14 @@ def syncForge65EclipseLaunches = tasks.register('syncForge65EclipseLaunches') { } tasks.matching { it.name == 'genEclipseRuns' }.configureEach { - finalizedBy syncForge65EclipseLaunches + finalizedBy syncForge66EclipseLaunches } def isolateEclipseProductionRuns = tasks.register('isolateEclipseProductionRuns') { group = 'ide' description = 'Prepares the complete ForgeGradle 7 Eclipse project configuration.' dependsOn tasks.named('genEclipseRuns') - dependsOn syncForge65EclipseLaunches + dependsOn syncForge66EclipseLaunches dependsOn configureEclipseBuildship dependsOn prepareEclipseResources } diff --git a/ci-fixtures/tools/README.md b/ci-fixtures/tools/README.md index 1365b42..a57c127 100644 --- a/ci-fixtures/tools/README.md +++ b/ci-fixtures/tools/README.md @@ -2,7 +2,7 @@ This directory contains a build-only derivative of MinecraftForge's MinecraftMavenizer `0.5.21`. It is used only while ForgeGradle prepares the -exact Forge `26.2-65.1.0` development dependency and is excluded from every +exact Forge `26.3-66.0.0` development dependency and is excluded from every OreSpawn publication artifact. ## Provenance and licence @@ -21,13 +21,13 @@ declaration and one accessor in that record. Missing, partial, duplicate or ambiguous states fail preparation. Targets without an explicit rule set are left unchanged. -Forge `26.2-65.1.0` compiles without source compatibility edits. Its explicit +Forge `26.3-66.0.0` compiles without source compatibility edits. Its explicit zero-rule entry proves that result is intentional and target-qualified rather than an accidental fall-through. A marker beside Mavenizer's output records the target and manifest SHA-256. Reprocessing the same source is idempotent. The derivative also propagates Gradle offline mode when the build sets -`ORESPAWN_MAVENIZER_OFFLINE=true`. Mavenizer, OreSpawn and Minecraft 26.2 all +`ORESPAWN_MAVENIZER_OFFLINE=true`. Mavenizer, Sky's Grass Slabs and Minecraft 26.3 all run and compile with Java 25. ## Rebuild diff --git a/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar b/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar index b5f7fb50b4efd168da56917d7ef34be60b184315..86aeb5ef2f658691a67b20ef6cfac3aeb787a8d2 100644 GIT binary patch delta 197 zcmWm8ISztA06@_}7R7zR4HsO{6WDtQ8%{vw0f?2w7%J;YjAx)SA@KnAT2R?patS}h ztN%~3yO!WAHCd9nG#;j-tk*LPPnL3(xwAj|<#!Z9T-E#LFXKp=uuw(?Hmazhjs}`& up^Xl@=)plB0}L_37%nE5Vum?9EKoF8Sf`QlzXzijii6z8CJpj!w*Lc;mQox5 delta 197 zcmWm8DGtIw06@_eI)$6X;<~RyVJl|0w!|E!$JW?lu$+m uRn$;N15Mayp^Xl@=)plB0}L_37!#z;8Rn6%+~3wnhXOBgv53568L$7a -Date: Fri, 28 Aug 2026 15:21:10 +0100 -Subject: [PATCH] Add target-aware source compatibility rules +From debd1358466af4d21ae25079ade85486fb267762 Mon Sep 17 00:00:00 2001 +From: JohnBraham +Date: Sat, 19 Sep 2026 16:12:24 +0100 +Subject: [PATCH] Qualify Mavenizer for Forge 26.3 --- build.gradle | 2 +- @@ -364,14 +364,14 @@ index 0000000..4d72d34 +} diff --git a/src/main/resources/META-INF/orespawn/minecraft-source-compatibility.json b/src/main/resources/META-INF/orespawn/minecraft-source-compatibility.json new file mode 100644 -index 0000000..702d759 +index 0000000..3451901 --- /dev/null +++ b/src/main/resources/META-INF/orespawn/minecraft-source-compatibility.json @@ -0,0 +1,9 @@ +{ + "schema": 1, + "targets": { -+ "net.minecraftforge:forge:26.2-65.1.0": { ++ "net.minecraftforge:forge:26.3-66.0.0": { + "expectedApplications": 0, + "rules": [] + } @@ -379,3 +379,4 @@ index 0000000..702d759 +} -- 2.55.0.windows.3 + diff --git a/ci-fixtures/tools/minecraft-source-compatibility.json b/ci-fixtures/tools/minecraft-source-compatibility.json index f6c049d..3451901 100644 --- a/ci-fixtures/tools/minecraft-source-compatibility.json +++ b/ci-fixtures/tools/minecraft-source-compatibility.json @@ -1,7 +1,7 @@ { "schema": 1, "targets": { - "net.minecraftforge:forge:26.2-65.1.0": { + "net.minecraftforge:forge:26.3-66.0.0": { "expectedApplications": 0, "rules": [] } diff --git a/docs/RELEASE-1.1.2.2603001.md b/docs/RELEASE-1.1.2.2603001.md new file mode 100644 index 0000000..6d1bc39 --- /dev/null +++ b/docs/RELEASE-1.1.2.2603001.md @@ -0,0 +1,12 @@ +# Sky's Grass Slabs 1.1.2 for Minecraft 26.3 + +This release brings the complete Sky's Grass Slabs feature set to Minecraft +26.3 and Forge 66. Dirt, grass and path slabs, turf, grass spreading, shovel +flattening and terrain smoothing retain their established behaviour. + +Existing Sky's Grass Slabs worlds and the supported older slab migrations +remain compatible. Back up an existing world before changing its Minecraft or +Forge version. + +Requires Minecraft 26.3, Forge 66.0.0 or a compatible Forge 66 build, and +Java 25. diff --git a/docs/WORLD-UPGRADES.md b/docs/WORLD-UPGRADES.md index a6cdd49..1d48e18 100644 --- a/docs/WORLD-UPGRADES.md +++ b/docs/WORLD-UPGRADES.md @@ -6,7 +6,7 @@ world has been checked in game. ## Sky's Grass Slabs content -Install `SkysGrassSlabs-1.1.2.2602001.jar` before opening a world that used an +Install `SkysGrassSlabs-1.1.2.2603001.jar` before opening a world that used an earlier release. The permanent dirt slab, grass slab, path slab and turf IDs are unchanged. @@ -70,8 +70,8 @@ When both mods remain installed, their content is left alone by default. See ## Modpack checklist 1. Back up the complete instance and world. -2. Update Forge and every required mod to a matching Minecraft 26.2 build. -3. Install the 26.2 Sky's Grass Slabs jar before the first upgraded start. +2. Update Forge and every required mod to a matching Minecraft 26.3 build. +3. Install the 26.3 Sky's Grass Slabs jar before the first upgraded start. 4. Read the complete Forge missing content list before confirming it. 5. Check representative slabs, turf, paths, inventories and old terrain. 6. Stop and start the upgraded copy once more, then repeat the checks. diff --git a/gradle.properties b/gradle.properties index fbd026a..be97f5a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -20,17 +20,17 @@ curseforge_project_id=1677588 ## Environment Properties # The Minecraft version must agree with the Forge version to get a valid artifact -minecraft_version=26.2 +minecraft_version=26.3 # The Minecraft version range can use any release version of Minecraft as bounds. # Snapshots, pre-releases, and release candidates are not guaranteed to sort properly # as they do not follow standard versioning conventions. -minecraft_version_range=[26.2,26.3,) +minecraft_version_range=[26.3,26.4,) # The Forge version must agree with the Minecraft version to get a valid artifact -forge_version=65.1.0 +forge_version=66.0.0 # The Forge version range can use any version of Forge as bounds or match the loader version range -forge_version_range=[65,) +forge_version_range=[66,) # The loader version range can only use the major version of Forge/FML as bounds -loader_version_range=[65,) +loader_version_range=[66,) # The mapping channel to use for mappings. # The default set of supported mapping channels are ["official", "snapshot", "snapshot_nodoc", "stable", "stable_nodoc"]. # Additional mapping channels can be registered through the "channelProviders" extension in a Gradle plugin. @@ -48,7 +48,7 @@ loader_version_range=[65,) mapping_channel=official # The mapping version to query from the mapping channel. # This must match the format required by the mapping channel. -mapping_version=26.2 +mapping_version=26.3 ## Mod Properties @@ -61,7 +61,7 @@ mod_name=Sky's Grass Slabs # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-2.1-only # The mod version. See https://semver.org/ -mod_version=1.1.2.2602001 +mod_version=1.1.2.2603001 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index dbe66e1..760c459 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=9c0f7faeeb306cb14e4279a3e084ca6b596894089a0638e68a07c945a32c9e14 -distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip +distributionSha256Sum=acd53f1edaf02f1a8ff99879f8a34b302661a057d9b063ae9e35b552f804d20a +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip networkTimeout=10000 retries=0 retryBackOffMs=500 diff --git a/src/gameTest/java/zone/moddev/mc/skysgrassslabs/gametest/SlabGameTests.java b/src/gameTest/java/zone/moddev/mc/skysgrassslabs/gametest/SlabGameTests.java index 51b8191..c182f5f 100644 --- a/src/gameTest/java/zone/moddev/mc/skysgrassslabs/gametest/SlabGameTests.java +++ b/src/gameTest/java/zone/moddev/mc/skysgrassslabs/gametest/SlabGameTests.java @@ -5,6 +5,7 @@ import net.minecraft.core.Direction; import net.minecraft.core.NonNullList; import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; import net.minecraft.gametest.framework.GameTestHelper; @@ -29,6 +30,7 @@ import net.minecraft.world.item.crafting.CraftingRecipe; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.BonemealSource; import net.minecraft.world.level.block.FenceBlock; import net.minecraft.world.level.block.SlabBlock; import net.minecraft.world.level.gamerules.GameRules; @@ -39,17 +41,17 @@ import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraftforge.common.Tags; -import net.minecraftforge.common.ToolActions; import net.minecraftforge.gametest.GameTest; import net.minecraftforge.gametest.GameTestNamespace; import net.minecraftforge.gametest.GameTestPrefix; import net.minecraftforge.event.entity.EntityJoinLevelEvent; -import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; import zone.moddev.mc.skysgrassslabs.SkysGrassSlabs; import zone.moddev.mc.skysgrassslabs.block.DirtSlabBlock; import zone.moddev.mc.skysgrassslabs.block.GrassSlabBlock; import zone.moddev.mc.skysgrassslabs.block.GrassSpread; import zone.moddev.mc.skysgrassslabs.block.PathSlabBlock; +import zone.moddev.mc.skysgrassslabs.block.SlabFlattening; import zone.moddev.mc.skysgrassslabs.block.TurfBlock; import zone.moddev.mc.skysgrassslabs.init.ModBlocks; import zone.moddev.mc.skysgrassslabs.init.ModRecipes; @@ -94,7 +96,6 @@ private static void setClockTime(GameTestHelper helper, int time) { @GameTest(structure = EMPTY) public static void shovelFlatteningPreservesOrientation(GameTestHelper helper) { BlockPos pos = helper.absolutePos(new BlockPos(1, 2, 1)); - UseOnContext context = context(helper, pos, new ItemStack(Items.IRON_SHOVEL)); BlockState dirtTop = ModBlocks.DIRT_SLAB.get().defaultBlockState() .setValue(SlabBlock.TYPE, SlabType.TOP); BlockState grassBottom = ModBlocks.GRASS_SLAB.get().defaultBlockState(); @@ -102,29 +103,33 @@ public static void shovelFlatteningPreservesOrientation(GameTestHelper helper) { BlockState doubled = dirtTop.setValue(SlabBlock.TYPE, SlabType.DOUBLE) .setValue(SlabBlock.WATERLOGGED, false); - BlockState topPath = dirtTop.getToolModifiedState(context, ToolActions.SHOVEL_FLATTEN, false); - BlockState bottomPath = grassBottom.getToolModifiedState(context, ToolActions.SHOVEL_FLATTEN, false); + Player player = helper.makeMockPlayer(GameType.SURVIVAL); + ItemStack shovel = new ItemStack(Items.IRON_SHOVEL); + player.setItemInHand(InteractionHand.MAIN_HAND, shovel); + + helper.getLevel().setBlock(pos, dirtTop, Block.UPDATE_ALL); + flatten(player, pos); + BlockState topPath = helper.getLevel().getBlockState(pos); require(helper, topPath != null && topPath.is(ModBlocks.PATH_SLAB.get()) && topPath.getValue(SlabBlock.TYPE) == SlabType.TOP, "top orientation was lost"); - require(helper, bottomPath != null && bottomPath.is(ModBlocks.PATH_SLAB.get()) + helper.getLevel().setBlock(pos, grassBottom, Block.UPDATE_ALL); + flatten(player, pos); + BlockState bottomPath = helper.getLevel().getBlockState(pos); + require(helper, bottomPath.is(ModBlocks.PATH_SLAB.get()) && bottomPath.getValue(SlabBlock.TYPE) == SlabType.BOTTOM, "bottom orientation was lost"); - require(helper, waterlogged.getToolModifiedState(context, - ToolActions.SHOVEL_FLATTEN, false) == null, "waterlogged dirt flattened"); - BlockState fullPath = doubled.getToolModifiedState(context, ToolActions.SHOVEL_FLATTEN, false); - require(helper, fullPath != null && fullPath.is(Blocks.DIRT_PATH), + helper.getLevel().setBlock(pos, waterlogged, Block.UPDATE_ALL); + flatten(player, pos); + require(helper, helper.getLevel().getBlockState(pos).equals(waterlogged), + "waterlogged dirt flattened"); + + helper.getLevel().setBlock(pos, doubled, Block.UPDATE_ALL); + flatten(player, pos); + BlockState fullPath = helper.getLevel().getBlockState(pos); + require(helper, fullPath.is(Blocks.DIRT_PATH), "double dirt slab did not normalize to vanilla path"); - - helper.getLevel().setBlock(pos, dirtTop, Block.UPDATE_ALL); - Player player = helper.makeMockPlayer(GameType.CREATIVE); - ItemStack shovel = new ItemStack(Items.IRON_SHOVEL); - player.setItemInHand(InteractionHand.MAIN_HAND, shovel); - shovel.useOn(new UseOnContext(player, InteractionHand.MAIN_HAND, - new BlockHitResult(Vec3.atCenterOf(pos), Direction.UP, pos, false))); - require(helper, helper.getLevel().getBlockState(pos).is(ModBlocks.PATH_SLAB.get()) - && helper.getLevel().getBlockState(pos).getValue(SlabBlock.TYPE) == SlabType.TOP, - "vanilla shovel use did not create a top path slab"); - require(helper, shovel.getDamageValue() == 1, "shovel durability was not consumed"); + require(helper, shovel.getDamageValue() == 3, + "successful slab flattening did not consume durability exactly once"); helper.succeed(); } @@ -288,9 +293,11 @@ public static void snowPlantsBonemealAndWaterAreTopAware(GameTestHelper helper) BlockState bottom = grass.defaultBlockState(); BlockState top = bottom.setValue(SlabBlock.TYPE, SlabType.TOP); - require(helper, !grass.isValidBonemealTarget(helper.getLevel(), pos, bottom), + require(helper, !grass.isValidBonemealTarget(helper.getLevel(), pos, bottom, + BonemealSource.INTERACTION), "bottom grass slab accepted bonemeal"); - require(helper, grass.isValidBonemealTarget(helper.getLevel(), pos, top), + require(helper, grass.isValidBonemealTarget(helper.getLevel(), pos, top, + BonemealSource.INTERACTION), "top grass slab rejected bonemeal"); require(helper, !grass.canSustainPlant(bottom, helper.getLevel(), pos, Direction.UP, (net.minecraftforge.common.IPlantable) Blocks.DANDELION), @@ -345,15 +352,15 @@ public static void snowPlantsBonemealAndWaterAreTopAware(GameTestHelper helper) require(helper, SkysGrassSlabsConfig.generateGrassSlabs(), "fresh common config did not default worldgen to true"); require(helper, Identifier.fromNamespaceAndPath(SkysGrassSlabs.MOD_ID, "dirt_slab") - .equals(ForgeRegistries.BLOCKS.getKey(ModBlocks.DIRT_SLAB.get())), + .equals(BuiltInRegistries.BLOCK.getKey(ModBlocks.DIRT_SLAB.get())), "dirt slab registry ID changed"); require(helper, Identifier.fromNamespaceAndPath(SkysGrassSlabs.MOD_ID, "grass_slab") - .equals(ForgeRegistries.BLOCKS.getKey(ModBlocks.GRASS_SLAB.get())), + .equals(BuiltInRegistries.BLOCK.getKey(ModBlocks.GRASS_SLAB.get())), "grass slab registry ID changed"); require(helper, Identifier.fromNamespaceAndPath(SkysGrassSlabs.MOD_ID, "path_slab") - .equals(ForgeRegistries.BLOCKS.getKey(ModBlocks.PATH_SLAB.get())), + .equals(BuiltInRegistries.BLOCK.getKey(ModBlocks.PATH_SLAB.get())), "path slab registry ID changed"); - require(helper, ForgeRegistries.FEATURES.containsKey( + require(helper, BuiltInRegistries.FEATURE_TYPE.containsKey( Identifier.fromNamespaceAndPath( SkysGrassSlabs.MOD_ID, "grass_slab_smoothing")), "worldgen feature registry ID changed"); @@ -597,13 +604,13 @@ public static void turfRecipeReturnsSoilAndUnchangedShovel(GameTestHelper helper require(helper, !recipe.matches(invalidGrid, helper.getLevel()), "turf recipe accepted a non-shovel"); require(helper, Identifier.fromNamespaceAndPath(SkysGrassSlabs.MOD_ID, "turf") - .equals(ForgeRegistries.BLOCKS.getKey(ModBlocks.TURF.get())), + .equals(BuiltInRegistries.BLOCK.getKey(ModBlocks.TURF.get())), "turf block registry ID changed"); require(helper, Identifier.fromNamespaceAndPath(SkysGrassSlabs.MOD_ID, "turf") - .equals(ForgeRegistries.ITEMS.getKey(ModBlocks.TURF_ITEM.get())), + .equals(BuiltInRegistries.ITEM.getKey(ModBlocks.TURF_ITEM.get())), "turf item registry ID changed"); require(helper, Identifier.fromNamespaceAndPath(SkysGrassSlabs.MOD_ID, "turf_cutting") - .equals(ForgeRegistries.RECIPE_SERIALIZERS.getKey(ModRecipes.TURF_CUTTING.get())), + .equals(BuiltInRegistries.RECIPE_SERIALIZER.getKey(ModRecipes.TURF_CUTTING.get())), "turf recipe serializer ID changed"); helper.succeed(); } @@ -661,7 +668,7 @@ public static void sheepEatTurfOnceAndRespectMobGriefing(GameTestHelper helper) sheep.setSheared(true); CommonEvents.addTurfEatingGoal(new EntityJoinLevelEvent(sheep, helper.getLevel())); CommonEvents.addTurfEatingGoal(new EntityJoinLevelEvent(sheep, helper.getLevel())); - long goalCount = sheep.goalSelector.getAvailableGoals().stream() + long goalCount = sheep.getGoalSelector().getAvailableGoals().stream() .filter(goal -> goal.getGoal() instanceof TurfEatingGoal).count(); require(helper, goalCount == 1, "sheep received duplicate turf eating goals"); @@ -718,17 +725,18 @@ private static ItemStack useTurfOn(Player player, BlockPos pos) { return turf; } - private static UseOnContext context(GameTestHelper helper, BlockPos pos, ItemStack stack) { - return new UseOnContext(helper.getLevel(), null, InteractionHand.MAIN_HAND, stack, - new BlockHitResult(Vec3.atCenterOf(pos), Direction.UP, pos, false)); - } - private static BlockPlaceContext placeContext(GameTestHelper helper, BlockPos pos, ItemStack stack) { return new BlockPlaceContext(helper.getLevel(), null, InteractionHand.MAIN_HAND, stack, new BlockHitResult(Vec3.atCenterOf(pos), Direction.UP, pos, false)); } + private static void flatten(Player player, BlockPos pos) { + SlabFlattening.handle(new PlayerInteractEvent.RightClickBlock(player, + InteractionHand.MAIN_HAND, pos, + new BlockHitResult(Vec3.atCenterOf(pos), Direction.UP, pos, false))); + } + private static void require(GameTestHelper helper, boolean condition, String message) { if (!condition) { helper.fail(message); diff --git a/src/gameTest/java/zone/moddev/mc/skysgrassslabs/gametest/WorldgenGameTests.java b/src/gameTest/java/zone/moddev/mc/skysgrassslabs/gametest/WorldgenGameTests.java index 4978838..a7a4f57 100644 --- a/src/gameTest/java/zone/moddev/mc/skysgrassslabs/gametest/WorldgenGameTests.java +++ b/src/gameTest/java/zone/moddev/mc/skysgrassslabs/gametest/WorldgenGameTests.java @@ -1,6 +1,6 @@ package zone.moddev.mc.skysgrassslabs.gametest; -import java.util.Optional; +import java.util.Set; import net.minecraft.core.BlockPos; import net.minecraft.gametest.framework.GameTestHelper; import net.minecraft.resources.Identifier; @@ -9,14 +9,11 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.levelgen.GenerationStep; -import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; -import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration; +import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.placement.PlacedFeature; import net.minecraftforge.gametest.GameTest; import net.minecraftforge.gametest.GameTestNamespace; import net.minecraftforge.gametest.GameTestPrefix; -import net.minecraftforge.common.world.BiomeModifier; -import net.minecraftforge.common.world.ModifiableBiomeInfo.BiomeInfo; import net.minecraftforge.registries.ForgeRegistries; import zone.moddev.mc.skysgrassslabs.SkysGrassSlabs; import zone.moddev.mc.skysgrassslabs.init.ModBlocks; @@ -40,14 +37,11 @@ public static void smoothingIsFirstVegetationFeature(GameTestHelper helper) { require(helper, modifier instanceof zone.moddev.mc.skysgrassslabs.world.SmoothingBiomeModifier, "registered smoothing biome modifier is missing"); - BiomeInfo.Builder builder = BiomeInfo.Builder.copyOf( - biome.value().modifiableBiomeInfo().getOriginalBiomeInfo()); - modifier.modify(biome, BiomeModifier.Phase.AFTER_EVERYTHING, builder); - var vegetation = builder.build().generationSettings().features() + var vegetation = biome.value().getGenerationSettings().features() .get(GenerationStep.Decoration.VEGETAL_DECORATION.ordinal()); require(helper, vegetation.size() > 0, "biome has no vegetation features"); PlacedFeature first = vegetation.get(0).value(); - require(helper, first.feature().value().feature() instanceof GrassSlabSmoothingFeature, + require(helper, first.feature().value() instanceof GrassSlabSmoothingFeature, "smoother is not the first vegetation feature"); helper.succeed(); } @@ -77,14 +71,12 @@ public static void smoothingIsBorderSafeAndIdempotent(GameTestHelper helper) { helper.getLevel().setBlock(chest, Blocks.CHEST.defaultBlockState(), Block.UPDATE_ALL); helper.runAfterDelay(5, () -> { - GrassSlabSmoothingFeature feature = new GrassSlabSmoothingFeature( - NoneFeatureConfiguration.CODEC); - FeaturePlaceContext context = new FeaturePlaceContext<>( - Optional.empty(), helper.getLevel(), + primeLoadedHeightmaps(helper, owner); + GrassSlabSmoothingFeature feature = new GrassSlabSmoothingFeature(); + require(helper, feature.place(helper.getLevel(), helper.getLevel().getChunkSource().getGenerator(), - RandomSource.create(19780401L), - center, NoneFeatureConfiguration.INSTANCE); - require(helper, feature.place(context), "controlled feature pass made no changes"); + RandomSource.create(19780401L), center), + "controlled feature pass made no changes"); require(helper, helper.getLevel().getBlockState(center.above()) .is(ModBlocks.GRASS_SLAB.get()), "one-block transition was not smoothed"); require(helper, helper.getLevel().getBlockState(border.above()) @@ -102,7 +94,9 @@ public static void smoothingIsBorderSafeAndIdempotent(GameTestHelper helper) { "block entity was overwritten"); int firstCount = countGrassSlabs(helper, owner); helper.runAfterDelay(10, () -> { - boolean secondChanged = feature.place(context); + boolean secondChanged = feature.place(helper.getLevel(), + helper.getLevel().getChunkSource().getGenerator(), + RandomSource.create(19780401L), center); int secondCount = countGrassSlabs(helper, owner); require(helper, !secondChanged && secondCount == firstCount, "settled second pass changed output: before=" + firstCount @@ -112,6 +106,17 @@ public static void smoothingIsBorderSafeAndIdempotent(GameTestHelper helper) { }); } + private static void primeLoadedHeightmaps(GameTestHelper helper, ChunkPos owner) { + for (int chunkX = owner.x() - 1; chunkX <= owner.x() + 1; chunkX++) { + for (int chunkZ = owner.z() - 1; chunkZ <= owner.z() + 1; chunkZ++) { + var chunk = helper.getLevel().getChunkSource().getChunkNow(chunkX, chunkZ); + if (chunk != null) { + Heightmap.primeHeightmaps(chunk, Set.of(Heightmap.Types.WORLD_SURFACE_WG)); + } + } + } + } + private static int countGrassSlabs(GameTestHelper helper, ChunkPos chunk) { int count = 0; BlockPos.MutableBlockPos cursor = new BlockPos.MutableBlockPos(); diff --git a/src/main/java/zone/moddev/mc/skysgrassslabs/SkysGrassSlabs.java b/src/main/java/zone/moddev/mc/skysgrassslabs/SkysGrassSlabs.java index d312f4c..97acbf7 100644 --- a/src/main/java/zone/moddev/mc/skysgrassslabs/SkysGrassSlabs.java +++ b/src/main/java/zone/moddev/mc/skysgrassslabs/SkysGrassSlabs.java @@ -27,7 +27,7 @@ public final class SkysGrassSlabs { /** Stable Forge mod identifier and resource namespace. */ public static final String MOD_ID = "skysgrassslabs"; public static final String NAME = "Sky's Grass Slabs"; - public static final String VERSION = "1.1.2.2602001"; + public static final String VERSION = "1.1.2.2603001"; public static final Logger LOGGER = LogManager.getLogger(); /** Registers content, configuration, world generation, and persistent state. */ diff --git a/src/main/java/zone/moddev/mc/skysgrassslabs/block/DirtSlabBlock.java b/src/main/java/zone/moddev/mc/skysgrassslabs/block/DirtSlabBlock.java index 5c22a77..8839c04 100644 --- a/src/main/java/zone/moddev/mc/skysgrassslabs/block/DirtSlabBlock.java +++ b/src/main/java/zone/moddev/mc/skysgrassslabs/block/DirtSlabBlock.java @@ -6,7 +6,6 @@ import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.ScheduledTickAccess; import net.minecraft.world.level.block.Block; @@ -14,7 +13,6 @@ import net.minecraft.world.level.block.SnowyBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; -import net.minecraftforge.common.ToolAction; /** Dirt slab with snow presentation and target-aware grass growth. */ public final class DirtSlabBlock extends SlabBlock { @@ -57,10 +55,4 @@ public void randomTick(BlockState state, ServerLevel level, BlockPos pos, Random GrassSpread.tickDirtSlab(level, pos, repaired, random); } - @Override - @Nullable - public BlockState getToolModifiedState(BlockState state, UseOnContext context, - ToolAction action, boolean simulate) { - return SlabTransitions.flatten(state, action); - } } diff --git a/src/main/java/zone/moddev/mc/skysgrassslabs/block/GrassSlabBlock.java b/src/main/java/zone/moddev/mc/skysgrassslabs/block/GrassSlabBlock.java index 8abad53..bee94d8 100644 --- a/src/main/java/zone/moddev/mc/skysgrassslabs/block/GrassSlabBlock.java +++ b/src/main/java/zone/moddev/mc/skysgrassslabs/block/GrassSlabBlock.java @@ -14,13 +14,13 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.BlockTags; import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.ScheduledTickAccess; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.BonemealSource; import net.minecraft.world.level.block.BonemealableBlock; import net.minecraft.world.level.block.SlabBlock; import net.minecraft.world.level.block.SnowyBlock; @@ -28,10 +28,9 @@ import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.SlabType; -import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.feature.Feature; import net.minecraft.world.level.levelgen.placement.PlacedFeature; import net.minecraftforge.common.IPlantable; -import net.minecraftforge.common.ToolAction; import zone.moddev.mc.skysgrassslabs.init.ModBlocks; /** Grass slab with target aware spreading and top slab vegetation behaviour. */ @@ -102,18 +101,9 @@ public void randomTick(BlockState state, ServerLevel level, BlockPos pos, Random GrassSpread.spreadFrom(level, pos, random, pos.below()); } - @Override - @Nullable - public BlockState getToolModifiedState(BlockState state, UseOnContext context, - ToolAction action, boolean simulate) { - - return SlabTransitions.flatten(state, action); - } - @Override public boolean canSustainPlant(BlockState state, BlockGetter level, BlockPos pos, Direction direction, IPlantable plantable) { - return state.getValue(TYPE) == SlabType.TOP && !state.getValue(WATERLOGGED) && direction == Direction.UP && Blocks.GRASS_BLOCK.canSustainPlant(Blocks.GRASS_BLOCK.defaultBlockState(), @@ -121,19 +111,22 @@ public boolean canSustainPlant(BlockState state, BlockGetter level, BlockPos pos } @Override - public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) { + public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state, + BonemealSource source) { return state.getValue(TYPE) == SlabType.TOP && !state.getValue(WATERLOGGED) && level.getBlockState(pos.above()).isAir(); } @Override - public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) { + public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, + BlockState state, BonemealSource source) { return state.getValue(TYPE) == SlabType.TOP && !state.getValue(WATERLOGGED); } @Override - public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) { - if (!isBonemealSuccess(level, random, pos, state)) { + public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, + BlockState state, BonemealSource source) { + if (!isBonemealSuccess(level, random, pos, state, source)) { return; } @@ -166,18 +159,18 @@ public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos if (current.is(vanillaGrass.getBlock()) && random.nextInt(10) == 0) { ((BonemealableBlock) vanillaGrass.getBlock()).performBonemeal(level, random, - target, current); + target, current, source); } if (current.isAir()) { if (random.nextInt(8) == 0) { - List> flowers = level.getBiome(target).value() + List flowers = level.getBiome(target).value() .getGenerationSettings().getBoneMealFeatures(); if (flowers.isEmpty()) { continue; } - ConfiguredFeature flower = flowers.get(random.nextInt(flowers.size())); + Feature flower = flowers.get(random.nextInt(flowers.size())); flower.place(level, level.getChunkSource().getGenerator(), random, target); } else if (grassFeature.isPresent()) { grassFeature.get().value().place(level, diff --git a/src/main/java/zone/moddev/mc/skysgrassslabs/block/SlabFlattening.java b/src/main/java/zone/moddev/mc/skysgrassslabs/block/SlabFlattening.java new file mode 100644 index 0000000..c1e9657 --- /dev/null +++ b/src/main/java/zone/moddev/mc/skysgrassslabs/block/SlabFlattening.java @@ -0,0 +1,65 @@ +package zone.moddev.mc.skysgrassslabs.block; + +import net.minecraft.advancements.triggers.CriteriaTriggers; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.component.DataComponents; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import zone.moddev.mc.skysgrassslabs.init.ModBlocks; +import zone.moddev.mc.skysgrassslabs.item.ShovelSupport; + +/** Orientation-aware slab flattening for the data-driven shovel contract. */ +public final class SlabFlattening { + private SlabFlattening() { + } + + public static boolean handle(PlayerInteractEvent.RightClickBlock event) { + ItemStack stack = event.getItemStack(); + if (!ShovelSupport.isShovel(stack) || event.getFace() == Direction.DOWN) { + return false; + } + + Level level = event.getLevel(); + BlockPos pos = event.getPos(); + BlockState current = level.getBlockState(pos); + if ((!current.is(ModBlocks.DIRT_SLAB.get()) && !current.is(ModBlocks.GRASS_SLAB.get())) + || !level.getBlockState(pos.above()).isAir()) { + return false; + } + + var player = event.getEntity(); + if (!level.mayInteract(player, pos) + || !player.mayUseItemAt(pos, event.getFace(), stack) + || event.getHand() == InteractionHand.MAIN_HAND + && player.getOffhandItem().has(DataComponents.BLOCKS_ATTACKS) + && !player.isSecondaryUseActive()) { + return false; + } + + BlockState flattened = SlabTransitions.flatten(current); + if (flattened == null) { + return false; + } + + if (player instanceof ServerPlayer serverPlayer) { + CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger(serverPlayer, pos, stack); + } + stack.hurtAndBreak(1, player, event.getHand().asEquipmentSlot()); + level.setBlock(pos, flattened, Block.UPDATE_ALL_IMMEDIATE); + level.playSound(player, pos, SoundEvents.SHOVEL_FLATTEN.value(), SoundSource.BLOCKS, + 1.0F, 1.0F); + level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(player, flattened)); + event.setCancellationResult(InteractionResult.SUCCESS); + return true; + } +} diff --git a/src/main/java/zone/moddev/mc/skysgrassslabs/block/SlabTransitions.java b/src/main/java/zone/moddev/mc/skysgrassslabs/block/SlabTransitions.java index 07b10f2..fc51d2e 100644 --- a/src/main/java/zone/moddev/mc/skysgrassslabs/block/SlabTransitions.java +++ b/src/main/java/zone/moddev/mc/skysgrassslabs/block/SlabTransitions.java @@ -6,8 +6,6 @@ import net.minecraft.world.level.block.SlabBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.SlabType; -import net.minecraftforge.common.ToolAction; -import net.minecraftforge.common.ToolActions; import zone.moddev.mc.skysgrassslabs.init.ModBlocks; /** Lossless state transitions shared by soil slabs. */ @@ -16,8 +14,8 @@ private SlabTransitions() { } @Nullable - static BlockState flatten(BlockState state, ToolAction action) { - if (action != ToolActions.SHOVEL_FLATTEN || state.getValue(SlabBlock.WATERLOGGED)) { + static BlockState flatten(BlockState state) { + if (state.getValue(SlabBlock.WATERLOGGED)) { return null; } diff --git a/src/main/java/zone/moddev/mc/skysgrassslabs/block/TurfBlockItem.java b/src/main/java/zone/moddev/mc/skysgrassslabs/block/TurfBlockItem.java index 3f9571e..fa4c7a2 100644 --- a/src/main/java/zone/moddev/mc/skysgrassslabs/block/TurfBlockItem.java +++ b/src/main/java/zone/moddev/mc/skysgrassslabs/block/TurfBlockItem.java @@ -56,7 +56,7 @@ public InteractionResult useOn(UseOnContext context) { CriteriaTriggers.PLACED_BLOCK.trigger(serverPlayer, pos, held); } - var sound = grass.getSoundType(level, pos, player); + var sound = grass.getSoundType(); level.playSound(player, pos, sound.getPlaceSound(), SoundSource.BLOCKS, (sound.getVolume() + 1.0F) / 2.0F, sound.getPitch() * 0.8F); diff --git a/src/main/java/zone/moddev/mc/skysgrassslabs/event/CommonEvents.java b/src/main/java/zone/moddev/mc/skysgrassslabs/event/CommonEvents.java index b6f1206..139e6d0 100644 --- a/src/main/java/zone/moddev/mc/skysgrassslabs/event/CommonEvents.java +++ b/src/main/java/zone/moddev/mc/skysgrassslabs/event/CommonEvents.java @@ -5,6 +5,8 @@ import java.util.WeakHashMap; import net.minecraft.world.entity.animal.sheep.Sheep; import net.minecraftforge.event.entity.EntityJoinLevelEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import zone.moddev.mc.skysgrassslabs.block.SlabFlattening; import zone.moddev.mc.skysgrassslabs.entity.ai.TurfEatingGoal; /** Server gameplay event registrations. */ @@ -14,6 +16,7 @@ public final class CommonEvents { public static void register() { EntityJoinLevelEvent.BUS.addListener(CommonEvents::addTurfEatingGoal); + PlayerInteractEvent.RightClickBlock.BUS.addListener(CommonEvents::flattenSlab); } public static void addTurfEatingGoal(EntityJoinLevelEvent event) { @@ -21,10 +24,14 @@ public static void addTurfEatingGoal(EntityJoinLevelEvent event) { return; } if (TURF_GOAL_SHEEP.add(sheep)) { - sheep.goalSelector.addGoal(5, new TurfEatingGoal(sheep)); + sheep.getGoalSelector().addGoal(5, new TurfEatingGoal(sheep)); } } + private static boolean flattenSlab(PlayerInteractEvent.RightClickBlock event) { + return SlabFlattening.handle(event); + } + private CommonEvents() { } } diff --git a/src/main/java/zone/moddev/mc/skysgrassslabs/init/ModBlocks.java b/src/main/java/zone/moddev/mc/skysgrassslabs/init/ModBlocks.java index 5b39f23..3771447 100644 --- a/src/main/java/zone/moddev/mc/skysgrassslabs/init/ModBlocks.java +++ b/src/main/java/zone/moddev/mc/skysgrassslabs/init/ModBlocks.java @@ -1,7 +1,7 @@ package zone.moddev.mc.skysgrassslabs.init; import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.CreativeModeTabs; +import net.minecraft.resources.Identifier; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -22,6 +22,8 @@ /** Stable block and item registrations. */ public final class ModBlocks { + private static final Identifier BUILDING_BLOCKS_TAB = + Identifier.withDefaultNamespace("building_blocks"); public static final DeferredRegister BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, SkysGrassSlabs.MOD_ID); public static final DeferredRegister ITEMS = @@ -88,7 +90,7 @@ private static RegistryObject slabItem(String name, RegistryObject } private static void buildCreativeTab(BuildCreativeModeTabContentsEvent event) { - if (CreativeModeTabs.BUILDING_BLOCKS.equals(event.getTabKey())) { + if (BUILDING_BLOCKS_TAB.equals(event.getTabKey().identifier())) { event.accept(DIRT_SLAB_ITEM); event.accept(GRASS_SLAB_ITEM); event.accept(PATH_SLAB_ITEM); diff --git a/src/main/java/zone/moddev/mc/skysgrassslabs/item/NormalizingSlabItem.java b/src/main/java/zone/moddev/mc/skysgrassslabs/item/NormalizingSlabItem.java index 8d41606..d1858fc 100644 --- a/src/main/java/zone/moddev/mc/skysgrassslabs/item/NormalizingSlabItem.java +++ b/src/main/java/zone/moddev/mc/skysgrassslabs/item/NormalizingSlabItem.java @@ -59,7 +59,7 @@ private InteractionResult combine(UseOnContext context, BlockPos pos) { if (!level.setBlock(pos, combined, Block.UPDATE_ALL_IMMEDIATE)) { return InteractionResult.FAIL; } - SoundType sound = combined.getSoundType(level, pos, player); + SoundType sound = combined.getSoundType(); level.playSound(player, pos, sound.getPlaceSound(), SoundSource.BLOCKS, (sound.getVolume() + 1.0F) / 2.0F, sound.getPitch() * 0.8F); if (!player.getAbilities().instabuild) { diff --git a/src/main/java/zone/moddev/mc/skysgrassslabs/item/ShovelSupport.java b/src/main/java/zone/moddev/mc/skysgrassslabs/item/ShovelSupport.java new file mode 100644 index 0000000..a1b750a --- /dev/null +++ b/src/main/java/zone/moddev/mc/skysgrassslabs/item/ShovelSupport.java @@ -0,0 +1,18 @@ +package zone.moddev.mc.skysgrassslabs.item; + +import net.minecraft.core.Holder; +import net.minecraft.core.component.BlockTransformer; +import net.minecraft.core.component.DataComponents; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.BlockTransformers; + +/** Target-native shovel detection shared by crafting and slab flattening. */ +public final class ShovelSupport { + private ShovelSupport() { + } + + public static boolean isShovel(ItemStack stack) { + Holder transformer = stack.get(DataComponents.BLOCK_TRANSFORMER); + return transformer != null && transformer.is(BlockTransformers.SHOVEL); + } +} diff --git a/src/main/java/zone/moddev/mc/skysgrassslabs/recipe/TurfCuttingRecipe.java b/src/main/java/zone/moddev/mc/skysgrassslabs/recipe/TurfCuttingRecipe.java index aa0f011..cb8cbe1 100644 --- a/src/main/java/zone/moddev/mc/skysgrassslabs/recipe/TurfCuttingRecipe.java +++ b/src/main/java/zone/moddev/mc/skysgrassslabs/recipe/TurfCuttingRecipe.java @@ -4,6 +4,7 @@ import java.util.List; import com.mojang.serialization.MapCodec; import net.minecraft.core.NonNullList; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; import net.minecraft.world.item.Item; @@ -18,11 +19,10 @@ import net.minecraft.world.item.crafting.display.ShapelessCraftingRecipeDisplay; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; -import net.minecraftforge.common.ToolActions; -import net.minecraftforge.registries.ForgeRegistries; import zone.moddev.mc.skysgrassslabs.compat.BuildingBricksCompat; import zone.moddev.mc.skysgrassslabs.init.ModBlocks; import zone.moddev.mc.skysgrassslabs.init.ModRecipes; +import zone.moddev.mc.skysgrassslabs.item.ShovelSupport; /** Cuts turf while returning the matching dirt and an unchanged shovel. */ public final class TurfCuttingRecipe extends CustomRecipe { @@ -121,14 +121,14 @@ public RecipeSerializer getSerializer() { } private static boolean isShovel(ItemStack stack) { - return stack.canPerformAction(ToolActions.SHOVEL_FLATTEN); + return ShovelSupport.isShovel(stack); } private static NonNullList createIngredients() { NonNullList result = NonNullList.create(); result.add(Ingredient.of(Blocks.GRASS_BLOCK, ModBlocks.GRASS_SLAB.get())); List shovels = new ArrayList<>(); - for (Item item : ForgeRegistries.ITEMS.getValues()) { + for (Item item : BuiltInRegistries.ITEM.stream().toList()) { ItemStack candidate = new ItemStack(item); if (isShovel(candidate)) { shovels.add(item); diff --git a/src/main/java/zone/moddev/mc/skysgrassslabs/world/GrassSlabSmoothingFeature.java b/src/main/java/zone/moddev/mc/skysgrassslabs/world/GrassSlabSmoothingFeature.java index 30e6c35..326edb2 100644 --- a/src/main/java/zone/moddev/mc/skysgrassslabs/world/GrassSlabSmoothingFeature.java +++ b/src/main/java/zone/moddev/mc/skysgrassslabs/world/GrassSlabSmoothingFeature.java @@ -1,6 +1,6 @@ package zone.moddev.mc.skysgrassslabs.world; -import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import java.util.Arrays; import net.minecraft.core.BlockPos; import net.minecraft.world.level.ChunkPos; @@ -14,35 +14,38 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.feature.Feature; -import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; -import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration; +import net.minecraft.util.RandomSource; import zone.moddev.mc.skysgrassslabs.compat.LegacyWorldDataHook; import zone.moddev.mc.skysgrassslabs.config.SkysGrassSlabsConfig; import zone.moddev.mc.skysgrassslabs.init.ModBlocks; /** Deterministic two-pass slope smoothing for newly generated Overworld chunks. */ -public final class GrassSlabSmoothingFeature extends Feature { +public final class GrassSlabSmoothingFeature implements Feature { + public static final MapCodec CODEC = + MapCodec.unit(GrassSlabSmoothingFeature::new); private static final int HALO_WIDTH = 18; private static final int MISSING = Integer.MIN_VALUE; private static final ThreadLocal BUFFERS = ThreadLocal.withInitial(DecisionBuffer::new); - public GrassSlabSmoothingFeature(Codec codec) { - super(codec); + @Override + public MapCodec codec() { + return CODEC; } @Override - public boolean place(FeaturePlaceContext context) { - WorldGenLevel level = context.level(); + public boolean place(WorldGenLevel level, ChunkGenerator generator, RandomSource random, + BlockPos origin) { if (!SkysGrassSlabsConfig.isSmoothingActive() || level.getLevel().dimension() != Level.OVERWORLD) { return false; } ChunkAccess owner = level instanceof WorldGenRegion region ? level.getChunk(region.getCenter().x(), region.getCenter().z()) - : level.getChunk(context.origin()); + : level.getChunk(origin); ChunkPos ownerPos = owner.getPos(); if (LegacyWorldDataHook.isLegacyChunk(ownerPos.x(), ownerPos.z())) { return false; diff --git a/src/main/java/zone/moddev/mc/skysgrassslabs/world/ModWorldState.java b/src/main/java/zone/moddev/mc/skysgrassslabs/world/ModWorldState.java index 902357b..2205622 100644 --- a/src/main/java/zone/moddev/mc/skysgrassslabs/world/ModWorldState.java +++ b/src/main/java/zone/moddev/mc/skysgrassslabs/world/ModWorldState.java @@ -91,7 +91,7 @@ static synchronized void relocateLegacyState(Path worldRoot) { Files.copy(oldFile, temporary, StandardCopyOption.REPLACE_EXISTING); Files.move(temporary, newFile, StandardCopyOption.ATOMIC_MOVE); SkysGrassSlabs.LOGGER.info("Preserved Sky's Grass Slabs world state in the " - + "current namespaced data directory"); + + "namespaced data directory"); } catch (IOException exception) { try { Files.deleteIfExists(temporary); @@ -99,7 +99,7 @@ static synchronized void relocateLegacyState(Path worldRoot) { exception.addSuppressed(cleanupFailure); } throw new IllegalStateException("Could not preserve existing Sky's Grass Slabs " - + "world state before loading the current Minecraft version", exception); + + "world state before loading this Minecraft version", exception); } } diff --git a/src/main/java/zone/moddev/mc/skysgrassslabs/world/SmoothingBiomeModifier.java b/src/main/java/zone/moddev/mc/skysgrassslabs/world/SmoothingBiomeModifier.java index 4a13c72..fb1e494 100644 --- a/src/main/java/zone/moddev/mc/skysgrassslabs/world/SmoothingBiomeModifier.java +++ b/src/main/java/zone/moddev/mc/skysgrassslabs/world/SmoothingBiomeModifier.java @@ -26,7 +26,7 @@ public void modify(Holder biome, Phase phase, BiomeInfo.Builder builder) || biome.is(BiomeTags.IS_NETHER) || biome.is(BiomeTags.IS_END)) { return; } - BiomeGenerationSettings.PlainBuilder generation = builder.getGenerationSettings(); + BiomeGenerationSettings.PlainBuilder generation = builder.generationSettings(); List> features = generation.getFeatures( GenerationStep.Decoration.VEGETAL_DECORATION); if (features.stream().noneMatch(existing -> existing.value() == smoothing.value())) { diff --git a/src/main/java/zone/moddev/mc/skysgrassslabs/world/WorldgenBootstrap.java b/src/main/java/zone/moddev/mc/skysgrassslabs/world/WorldgenBootstrap.java index 8eff99f..3e7a291 100644 --- a/src/main/java/zone/moddev/mc/skysgrassslabs/world/WorldgenBootstrap.java +++ b/src/main/java/zone/moddev/mc/skysgrassslabs/world/WorldgenBootstrap.java @@ -3,9 +3,8 @@ import com.mojang.serialization.MapCodec; import java.util.Collections; import net.minecraft.core.Holder; -import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.core.registries.Registries; import net.minecraft.world.level.levelgen.feature.Feature; -import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration; import net.minecraft.world.level.levelgen.placement.PlacedFeature; import net.minecraftforge.common.world.BiomeModifier; import net.minecraftforge.eventbus.api.bus.BusGroup; @@ -19,14 +18,13 @@ public final class WorldgenBootstrap { public static final String FEATURE_NAME = "grass_slab_smoothing"; - private static final DeferredRegister> FEATURES = - DeferredRegister.create(ForgeRegistries.FEATURES, SkysGrassSlabs.MOD_ID); + private static final DeferredRegister> FEATURE_TYPES = + DeferredRegister.create(Registries.FEATURE_TYPE, SkysGrassSlabs.MOD_ID); private static final DeferredRegister> BIOME_MODIFIERS = DeferredRegister.create(ForgeRegistries.Keys.BIOME_MODIFIER_SERIALIZERS, SkysGrassSlabs.MOD_ID); - private static final RegistryObject SMOOTHING = - FEATURES.register(FEATURE_NAME, - () -> new GrassSlabSmoothingFeature(NoneFeatureConfiguration.CODEC)); + private static final RegistryObject> SMOOTHING = + FEATURE_TYPES.register(FEATURE_NAME, () -> GrassSlabSmoothingFeature.CODEC); private static volatile Holder placedFeature; @@ -38,7 +36,7 @@ private WorldgenBootstrap() { } public static void register(BusGroup modBusGroup) { - FEATURES.register(modBusGroup); + FEATURE_TYPES.register(modBusGroup); BIOME_MODIFIERS.register(modBusGroup); FMLCommonSetupEvent.getBus(modBusGroup).addListener(WorldgenBootstrap::commonSetup); } @@ -49,10 +47,8 @@ private static void commonSetup(FMLCommonSetupEvent event) { static synchronized Holder placedFeature() { if (placedFeature == null) { - Holder> configured = Holder.direct( - new ConfiguredFeature( - SMOOTHING.get(), NoneFeatureConfiguration.INSTANCE)); - placedFeature = Holder.direct(new PlacedFeature(configured, Collections.emptyList())); + Holder feature = Holder.direct(new GrassSlabSmoothingFeature()); + placedFeature = Holder.direct(new PlacedFeature(feature, Collections.emptyList())); } return placedFeature; } diff --git a/src/main/resources/data/skysgrassslabs/advancement/recipes/dirt_slab.json b/src/main/resources/data/skysgrassslabs/advancement/recipes/dirt_slab.json index 52b8d50..9b28bbd 100644 --- a/src/main/resources/data/skysgrassslabs/advancement/recipes/dirt_slab.json +++ b/src/main/resources/data/skysgrassslabs/advancement/recipes/dirt_slab.json @@ -8,7 +8,7 @@ }, "has_the_recipe": { "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "skysgrassslabs:dirt_slab" } + "conditions": { "recipes": "skysgrassslabs:dirt_slab" } } }, "requirements": [["has_dirt", "has_the_recipe"]] diff --git a/src/main/resources/data/skysgrassslabs/advancement/recipes/grass_block_from_seeds.json b/src/main/resources/data/skysgrassslabs/advancement/recipes/grass_block_from_seeds.json index 12c8b69..11f1e1a 100644 --- a/src/main/resources/data/skysgrassslabs/advancement/recipes/grass_block_from_seeds.json +++ b/src/main/resources/data/skysgrassslabs/advancement/recipes/grass_block_from_seeds.json @@ -8,7 +8,7 @@ }, "has_the_recipe": { "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "skysgrassslabs:grass_block_from_seeds" } + "conditions": { "recipes": "skysgrassslabs:grass_block_from_seeds" } } }, "requirements": [["has_dirt", "has_the_recipe"]] diff --git a/src/main/resources/data/skysgrassslabs/advancement/recipes/grass_slab.json b/src/main/resources/data/skysgrassslabs/advancement/recipes/grass_slab.json index c0234a0..f7f0d92 100644 --- a/src/main/resources/data/skysgrassslabs/advancement/recipes/grass_slab.json +++ b/src/main/resources/data/skysgrassslabs/advancement/recipes/grass_slab.json @@ -8,7 +8,7 @@ }, "has_the_recipe": { "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "skysgrassslabs:grass_slab" } + "conditions": { "recipes": "skysgrassslabs:grass_slab" } } }, "requirements": [["has_grass_block", "has_the_recipe"]] diff --git a/src/main/resources/data/skysgrassslabs/advancement/recipes/grass_slab_from_seeds.json b/src/main/resources/data/skysgrassslabs/advancement/recipes/grass_slab_from_seeds.json index cb5adc0..615e35e 100644 --- a/src/main/resources/data/skysgrassslabs/advancement/recipes/grass_slab_from_seeds.json +++ b/src/main/resources/data/skysgrassslabs/advancement/recipes/grass_slab_from_seeds.json @@ -8,7 +8,7 @@ }, "has_the_recipe": { "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "skysgrassslabs:grass_slab_from_seeds" } + "conditions": { "recipes": "skysgrassslabs:grass_slab_from_seeds" } } }, "requirements": [["has_dirt_slab", "has_the_recipe"]] diff --git a/src/main/resources/data/skysgrassslabs/advancement/recipes/turf.json b/src/main/resources/data/skysgrassslabs/advancement/recipes/turf.json index 125a996..7fbfbcf 100644 --- a/src/main/resources/data/skysgrassslabs/advancement/recipes/turf.json +++ b/src/main/resources/data/skysgrassslabs/advancement/recipes/turf.json @@ -12,7 +12,7 @@ }, "has_the_recipe": { "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "skysgrassslabs:turf" } + "conditions": { "recipes": "skysgrassslabs:turf" } } }, "requirements": [["has_grass_block", "has_grass_slab", "has_the_recipe"]] diff --git a/src/main/resources/data/skysgrassslabs/loot_table/blocks/dirt_slab.json b/src/main/resources/data/skysgrassslabs/loot_table/blocks/dirt_slab.json index 90bc9a2..c4a36e3 100644 --- a/src/main/resources/data/skysgrassslabs/loot_table/blocks/dirt_slab.json +++ b/src/main/resources/data/skysgrassslabs/loot_table/blocks/dirt_slab.json @@ -1,24 +1,27 @@ { "type": "minecraft:block", - "pools": [{ - "rolls": 1.0, - "bonus_rolls": 0.0, - "entries": [{ - "type": "minecraft:item", - "name": "skysgrassslabs:dirt_slab", - "functions": [ + "pools": [ + { + "entries": [ { - "function": "minecraft:set_count", - "conditions": [{ - "condition": "minecraft:block_state_property", - "block": "skysgrassslabs:dirt_slab", - "properties": { "type": "double" } - }], - "count": 2.0, - "add": false - }, - { "function": "minecraft:explosion_decay" } - ] - }] - }] + "type": "minecraft:item", + "modifier": [ + { + "type": "minecraft:set_count", + "condition": { + "type": "minecraft:match_block", + "blocks": "skysgrassslabs:dirt_slab", + "state": { "type": "double" } + }, + "count": 2 + }, + { "type": "minecraft:explosion_decay" } + ], + "name": "skysgrassslabs:dirt_slab" + } + ], + "rolls": 1 + } + ], + "random_sequence": "skysgrassslabs:blocks/dirt_slab" } diff --git a/src/main/resources/data/skysgrassslabs/loot_table/blocks/grass_slab.json b/src/main/resources/data/skysgrassslabs/loot_table/blocks/grass_slab.json index 2224f73..fa3aa1e 100644 --- a/src/main/resources/data/skysgrassslabs/loot_table/blocks/grass_slab.json +++ b/src/main/resources/data/skysgrassslabs/loot_table/blocks/grass_slab.json @@ -1,52 +1,48 @@ { "type": "minecraft:block", - "pools": [{ - "rolls": 1.0, - "bonus_rolls": 0.0, - "entries": [{ - "type": "minecraft:alternatives", - "children": [ + "pools": [ + { + "entries": [ { - "type": "minecraft:item", - "name": "skysgrassslabs:grass_slab", - "conditions": [{ - "condition": "minecraft:match_tool", - "predicate": { - "predicates": { - "minecraft:enchantments": [{ - "enchantments": "minecraft:silk_touch", - "levels": { "min": 1 } - }] - } + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "condition": "minecraft:tool/can_silk_touch", + "modifier": [ + { + "type": "minecraft:set_count", + "condition": { + "type": "minecraft:match_block", + "blocks": "skysgrassslabs:grass_slab", + "state": { "type": "double" } + }, + "count": 2 + } + ], + "name": "skysgrassslabs:grass_slab" + }, + { + "type": "minecraft:item", + "condition": { "type": "minecraft:survives_explosion" }, + "modifier": [ + { + "type": "minecraft:set_count", + "condition": { + "type": "minecraft:match_block", + "blocks": "skysgrassslabs:grass_slab", + "state": { "type": "double" } + }, + "count": 2 + } + ], + "name": "skysgrassslabs:dirt_slab" } - }], - "functions": [{ - "function": "minecraft:set_count", - "conditions": [{ - "condition": "minecraft:block_state_property", - "block": "skysgrassslabs:grass_slab", - "properties": { "type": "double" } - }], - "count": 2.0, - "add": false - }] - }, - { - "type": "minecraft:item", - "name": "skysgrassslabs:dirt_slab", - "conditions": [{ "condition": "minecraft:survives_explosion" }], - "functions": [{ - "function": "minecraft:set_count", - "conditions": [{ - "condition": "minecraft:block_state_property", - "block": "skysgrassslabs:grass_slab", - "properties": { "type": "double" } - }], - "count": 2.0, - "add": false - }] + ] } - ] - }] - }] + ], + "rolls": 1 + } + ], + "random_sequence": "skysgrassslabs:blocks/grass_slab" } diff --git a/src/main/resources/data/skysgrassslabs/loot_table/blocks/path_slab.json b/src/main/resources/data/skysgrassslabs/loot_table/blocks/path_slab.json index 7cd841e..687f919 100644 --- a/src/main/resources/data/skysgrassslabs/loot_table/blocks/path_slab.json +++ b/src/main/resources/data/skysgrassslabs/loot_table/blocks/path_slab.json @@ -1,22 +1,27 @@ { "type": "minecraft:block", - "pools": [{ - "rolls": 1.0, - "bonus_rolls": 0.0, - "entries": [{ - "type": "minecraft:item", - "name": "skysgrassslabs:dirt_slab", - "conditions": [{ "condition": "minecraft:survives_explosion" }], - "functions": [{ - "function": "minecraft:set_count", - "conditions": [{ - "condition": "minecraft:block_state_property", - "block": "skysgrassslabs:path_slab", - "properties": { "type": "double" } - }], - "count": 2.0, - "add": false - }] - }] - }] + "pools": [ + { + "entries": [ + { + "type": "minecraft:item", + "condition": { "type": "minecraft:survives_explosion" }, + "modifier": [ + { + "type": "minecraft:set_count", + "condition": { + "type": "minecraft:match_block", + "blocks": "skysgrassslabs:path_slab", + "state": { "type": "double" } + }, + "count": 2 + } + ], + "name": "skysgrassslabs:dirt_slab" + } + ], + "rolls": 1 + } + ], + "random_sequence": "skysgrassslabs:blocks/path_slab" } diff --git a/src/main/resources/data/skysgrassslabs/loot_table/blocks/turf.json b/src/main/resources/data/skysgrassslabs/loot_table/blocks/turf.json index 8c5d9a2..5b06db2 100644 --- a/src/main/resources/data/skysgrassslabs/loot_table/blocks/turf.json +++ b/src/main/resources/data/skysgrassslabs/loot_table/blocks/turf.json @@ -2,13 +2,12 @@ "type": "minecraft:block", "pools": [ { - "rolls": 1, + "condition": { "type": "minecraft:survives_explosion" }, "entries": [ { "type": "minecraft:item", "name": "skysgrassslabs:turf" } ], - "conditions": [ - { "condition": "minecraft:survives_explosion" } - ] + "rolls": 1 } - ] + ], + "random_sequence": "skysgrassslabs:blocks/turf" } diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index 9b39dd9..97e29b4 100644 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -1,10 +1,7 @@ { "pack": { "description": "${mod_id} resources", - "max_format": 107, - "min_format": [ - 107, - 1 - ] + "max_format": 121, + "min_format": 121 } } diff --git a/src/test/java/zone/moddev/mc/skysgrassslabs/ForwardUpgradeFixtureContractTest.java b/src/test/java/zone/moddev/mc/skysgrassslabs/ForwardUpgradeFixtureContractTest.java index 306aa10..60765be 100644 --- a/src/test/java/zone/moddev/mc/skysgrassslabs/ForwardUpgradeFixtureContractTest.java +++ b/src/test/java/zone/moddev/mc/skysgrassslabs/ForwardUpgradeFixtureContractTest.java @@ -80,6 +80,10 @@ public class ForwardUpgradeFixtureContractTest { new Fixture("26.1.2", "1.1.0.2601021", "0AFFA1D367F8582BD77F83830FA872D6C441B2DD1D6EB8D0AAA979D6CF760F6F", "EE631FF66EF3AD11DF1F48D562C19762DB84AE2E603839CBA7A51044F99ACF5A", 11, + true, true), + new Fixture("26.2", "1.1.2.2602001", + "040A997B439F2367A765B1B914C6B190B3B0382A3C8EBB846123B7B1DA5042AF", + "647838AE25835DD2B4C4E06BDBBD3D6040F229718CB59347EC8B75806FC504EB", 11, true, true) }; diff --git a/src/test/java/zone/moddev/mc/skysgrassslabs/ProjectContractTest.java b/src/test/java/zone/moddev/mc/skysgrassslabs/ProjectContractTest.java index de174bb..8100b5a 100644 --- a/src/test/java/zone/moddev/mc/skysgrassslabs/ProjectContractTest.java +++ b/src/test/java/zone/moddev/mc/skysgrassslabs/ProjectContractTest.java @@ -18,10 +18,10 @@ public void metadataUsesStableIdentityWithoutOreSpawnDependency() throws Excepti String properties = Files.readString(Path.of("gradle.properties"), StandardCharsets.UTF_8); assertTrue(properties.contains("mod_id=skysgrassslabs")); - assertTrue(properties.contains("minecraft_version=26.2")); - assertTrue(properties.contains("forge_version=65.1.0")); + assertTrue(properties.contains("minecraft_version=26.3")); + assertTrue(properties.contains("forge_version=66.0.0")); assertTrue(properties.contains("mapping_channel=official")); - assertTrue(properties.contains("mapping_version=26.2")); + assertTrue(properties.contains("mapping_version=26.3")); assertTrue(properties.contains("java_toolchain_version=25.0.3+9")); String build = Files.readString(Path.of("build.gradle"), StandardCharsets.UTF_8); assertTrue(build.contains("verifyJava25Toolchain")); @@ -36,14 +36,14 @@ public void playerAndMaintainerDocumentsExist() { assertTrue(Files.isRegularFile(Path.of("docs/GAMEPLAY.md"))); assertTrue(Files.isRegularFile(Path.of("docs/WORLD-UPGRADES.md"))); assertFalse(Files.exists(Path.of("docs/REPOSITORY.md"))); - assertTrue(Files.isRegularFile(Path.of("docs/RELEASE-1.1.2.2602001.md"))); + assertTrue(Files.isRegularFile(Path.of("docs/RELEASE-1.1.2.2603001.md"))); assertTrue(Files.isRegularFile(Path.of("docs/BETA-0.2.0.118021.md"))); } @Test public void releaseIdentityAndLicenseAreStable() throws Exception { String properties = Files.readString(Path.of("gradle.properties"), StandardCharsets.UTF_8); - assertTrue(properties.contains("mod_version=1.1.2.2602001")); + assertTrue(properties.contains("mod_version=1.1.2.2603001")); assertTrue(properties.contains("mod_license=LGPL-2.1-only")); assertEquals("LGPL-2.1-only", Files.readString(Path.of("LICENSE.spdx"), StandardCharsets.UTF_8).trim()); assertTrue(Files.readString(Path.of("NOTICE"), StandardCharsets.UTF_8) @@ -65,7 +65,7 @@ public void releaseDispatcherIsExplicitAndUsesTheImmutableBundle() throws Except digits = digits.substring(0, digits.length() - 2); int minor = Integer.parseInt(digits.substring(digits.length() - 2)); int major = Integer.parseInt(digits.substring(0, digits.length() - 2)); - assertEquals("master-26.2", "master-" + major + "." + minor + assertEquals("master-26.3", "master-" + major + "." + minor + (patch == 0 ? "" : "." + patch)); assertTrue(workflow.contains("target_suffix=\"${BASH_REMATCH[1]}\"")); assertTrue(workflow.contains("\"master-$mc_major.$mc_minor.$mc_patch$loader_suffix\"")); @@ -112,7 +112,7 @@ public void commonConfigAndWorldStateUsePermanentKeys() throws Exception { assertTrue(config.contains("push(\"compat\")")); assertTrue(config.contains("define(FORCE_REPLACE_BUILDINGBRICKS_SLABS, false)")); assertTrue(config.contains("define(FORCE_REPLACE_GRASS_SLABS_MOD_CONTENT, false)")); - assertTrue(main.contains("VERSION = \"1.1.2.2602001\"")); + assertTrue(main.contains("VERSION = \"1.1.2.2603001\"")); assertTrue(state.contains("skysgrassslabs_world_state")); assertTrue(state.contains("SCHEMA_VERSION = 1")); assertTrue(state.contains("schema_version")); @@ -219,7 +219,7 @@ public void acceptedRenderingAndRecipeContractsRemainVisible() throws Exception assertTrue(recipe.contains("MapCodec")); assertTrue(recipe.contains("StreamCodec")); assertTrue(recipe.contains("return false;")); - assertTrue(recipe.contains("canPerformAction(ToolActions.SHOVEL_FLATTEN)")); + assertTrue(recipe.contains("ShovelSupport.isShovel(stack)")); assertFalse(client.contains("ItemBlockRenderTypes")); assertTrue(client.contains("@SubscribeEvent\n" + " public static void registerBlockColors(RegisterColorHandlersEvent.Block event)")); @@ -239,7 +239,7 @@ public void acceptedRenderingAndRecipeContractsRemainVisible() throws Exception } @Test - public void forge65LifecycleAndDataPackContractsArePresent() throws Exception { + public void forge66LifecycleAndDataPackContractsArePresent() throws Exception { String blocks = Files.readString(Path.of( "src/main/java/zone/moddev/mc/skysgrassslabs/init/ModBlocks.java"), StandardCharsets.UTF_8); @@ -264,9 +264,9 @@ public void forge65LifecycleAndDataPackContractsArePresent() throws Exception { assertTrue(modifier.contains("BiomeTags.IS_END")); assertTrue(modifierJson.contains("skysgrassslabs:grass_slab_smoothing")); assertTrue(worldgen.contains("DeferredRegister>")); - assertTrue(pack.contains("\"max_format\": 107")); + assertTrue(pack.contains("\"max_format\": 121")); assertTrue(pack.contains("\"min_format\":")); - assertTrue(pack.contains("107")); + assertTrue(pack.contains("121")); for (String recipeName : new String[] {"dirt_slab", "grass_slab", "grass_block_from_seeds", "grass_slab_from_seeds", "turf"}) { @@ -295,13 +295,13 @@ public void continuousIntegrationTargetsTheStableBranchAndArtifacts() throws Exc "validate-gradle-build.yml"}) { String workflow = Files.readString(Path.of(".github/workflows", name), StandardCharsets.UTF_8); - assertTrue(name, workflow.contains("master-26.2")); + assertTrue(name, workflow.contains("master-26.3")); } String ci = Files.readString(Path.of(".github/workflows/ci.yml"), StandardCharsets.UTF_8); - assertTrue(ci.contains("SkysGrassSlabs-1.1.2.2602001.jar")); - assertTrue(ci.contains("SkysGrassSlabs-1.1.2.2602001-sources.jar")); - assertTrue(ci.contains("SkysGrassSlabs-1.1.2.2602001-javadoc.jar")); + assertTrue(ci.contains("SkysGrassSlabs-1.1.2.2603001.jar")); + assertTrue(ci.contains("SkysGrassSlabs-1.1.2.2603001-sources.jar")); + assertTrue(ci.contains("SkysGrassSlabs-1.1.2.2603001-javadoc.jar")); assertTrue(ci.contains("if-no-files-found: error")); assertEquals(0, ci.lines() .filter(line -> line.contains("java-version: '8.0.502+7'")) @@ -319,9 +319,9 @@ public void continuousIntegrationTargetsTheStableBranchAndArtifacts() throws Exc @Test public void adjacentUpgradeFixtureIsTracked() { assertTrue(Files.isRegularFile(Path.of("src/test/resources/fixtures/" - + "skysgrassslabs-26.1.2-forward-world.zip"))); + + "skysgrassslabs-26.2-forward-world.zip"))); assertTrue(Files.isRegularFile(Path.of("src/test/resources/fixtures/" - + "skysgrassslabs-26.1.2-forward-world.manifest"))); + + "skysgrassslabs-26.2-forward-world.manifest"))); assertTrue(Files.isRegularFile(Path.of("src/test/resources/fixtures/" + "grassslabs-1.18.2-migration-world.zip"))); assertTrue(Files.isRegularFile(Path.of("src/test/resources/fixtures/" diff --git a/src/test/java/zone/moddev/mc/skysgrassslabs/ResourceContractTest.java b/src/test/java/zone/moddev/mc/skysgrassslabs/ResourceContractTest.java index 1065735..fcd0e74 100644 --- a/src/test/java/zone/moddev/mc/skysgrassslabs/ResourceContractTest.java +++ b/src/test/java/zone/moddev/mc/skysgrassslabs/ResourceContractTest.java @@ -104,9 +104,7 @@ public void snowyGrassSlabModelsUseUntintedSnowCaps() throws Exception { public void grassSlabUsesComponentAwareSilkTouchPredicate() throws Exception { String loot = Files.readString(Path.of( "src/main/resources/data/skysgrassslabs/loot_table/blocks/grass_slab.json")); - assertTrue(loot.contains("\"predicates\"")); - assertTrue(loot.contains("\"minecraft:enchantments\"")); - assertTrue(loot.contains("\"enchantments\": \"minecraft:silk_touch\"")); + assertTrue(loot.contains("\"condition\": \"minecraft:tool/can_silk_touch\"")); } @Test @@ -117,7 +115,7 @@ public void turfRecipeUsesStableCustomSerializer() throws Exception { assertFalse(recipe.contains("\"category\":")); String implementation = Files.readString(Path.of( "src/main/java/zone/moddev/mc/skysgrassslabs/recipe/TurfCuttingRecipe.java")); - assertTrue(implementation.contains("canPerformAction(ToolActions.SHOVEL_FLATTEN)")); + assertTrue(implementation.contains("ShovelSupport.isShovel(stack)")); assertTrue(implementation.contains("Ingredient.of(ModBlocks.TURF_ITEM.get()).display()")); assertTrue(implementation.contains("Ingredient.of(Blocks.CRAFTING_TABLE).display()")); assertFalse(implementation.contains("SlotDisplay.ItemSlotDisplay")); diff --git a/src/test/resources/fixtures/skysgrassslabs-26.2-forward-world.manifest b/src/test/resources/fixtures/skysgrassslabs-26.2-forward-world.manifest new file mode 100644 index 0000000..ce8d838 --- /dev/null +++ b/src/test/resources/fixtures/skysgrassslabs-26.2-forward-world.manifest @@ -0,0 +1,8 @@ +fixture=skysgrassslabs-26.2-forward-world.zip +fixture_sha256=040A997B439F2367A765B1B914C6B190B3B0382A3C8EBB846123B7B1DA5042AF +fixture_bytes=95080 +fixture_entries=8 +source_minecraft=26.2 +source_mod_version=1.1.2.2602001 +source_jar_sha256=647838AE25835DD2B4C4E06BDBBD3D6040F229718CB59347EC8B75806FC504EB +generator=Accepted 26.1.2 fixture upgraded and saved twice with the accepted 26.2 jar diff --git a/src/test/resources/fixtures/skysgrassslabs-26.2-forward-world.zip b/src/test/resources/fixtures/skysgrassslabs-26.2-forward-world.zip new file mode 100644 index 0000000000000000000000000000000000000000..66a6a7d23d90e0fb8b21f2762aefcb4280e36d8a GIT binary patch literal 95080 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 literal 0 HcmV?d00001 diff --git a/src/upgradeIntegrationTest/installed-grassslabs/META-INF/mods.toml b/src/upgradeIntegrationTest/installed-grassslabs/META-INF/mods.toml index 2a36210..0c4c0c5 100644 --- a/src/upgradeIntegrationTest/installed-grassslabs/META-INF/mods.toml +++ b/src/upgradeIntegrationTest/installed-grassslabs/META-INF/mods.toml @@ -17,34 +17,34 @@ description='''Build-only saved-world compatibility verification.''' [[dependencies.skysgrassslabsupgradeprobe]] modId="forge" mandatory=true -versionRange="[65.1.0,66)" +versionRange="[66.0.0,67)" ordering="NONE" side="SERVER" [[dependencies.skysgrassslabsupgradeprobe]] modId="skysgrassslabs" mandatory=true -versionRange="[1.1.2.2602001]" +versionRange="[1.1.2.2603001]" ordering="AFTER" side="SERVER" [[dependencies.skysgrassslabsupgradeprobe]] modId="minecraft" mandatory=true -versionRange="[26.2,26.3,)" +versionRange="[26.3,26.4,)" ordering="NONE" side="SERVER" [[dependencies.grassslabs]] modId="forge" mandatory=true -versionRange="[65.1.0,66)" +versionRange="[66.0.0,67)" ordering="NONE" side="SERVER" [[dependencies.grassslabs]] modId="minecraft" mandatory=true -versionRange="[26.2,26.3,)" +versionRange="[26.3,26.4,)" ordering="NONE" side="SERVER" diff --git a/src/upgradeIntegrationTest/installed-grassslabs/pack.mcmeta b/src/upgradeIntegrationTest/installed-grassslabs/pack.mcmeta index 8699eed..3c2e4cb 100644 --- a/src/upgradeIntegrationTest/installed-grassslabs/pack.mcmeta +++ b/src/upgradeIntegrationTest/installed-grassslabs/pack.mcmeta @@ -2,7 +2,7 @@ "pack": { "description": "Sky's Grass Slabs build-only installed-mod verification", "min_format": [101, 1], - "max_format": 107, - "min_format": [107, 1] + "max_format": 121, + "min_format": 121 } } diff --git a/src/upgradeIntegrationTest/resources/META-INF/mods.toml b/src/upgradeIntegrationTest/resources/META-INF/mods.toml index bda2b92..918e241 100644 --- a/src/upgradeIntegrationTest/resources/META-INF/mods.toml +++ b/src/upgradeIntegrationTest/resources/META-INF/mods.toml @@ -11,20 +11,20 @@ description='''Build-only saved-world compatibility verification.''' [[dependencies.skysgrassslabsupgradeprobe]] modId="forge" mandatory=true -versionRange="[65.1.0,66)" +versionRange="[66.0.0,67)" ordering="NONE" side="SERVER" [[dependencies.skysgrassslabsupgradeprobe]] modId="skysgrassslabs" mandatory=true -versionRange="[1.1.2.2602001]" +versionRange="[1.1.2.2603001]" ordering="AFTER" side="SERVER" [[dependencies.skysgrassslabsupgradeprobe]] modId="minecraft" mandatory=true -versionRange="[26.2,26.3,)" +versionRange="[26.3,26.4,)" ordering="NONE" side="SERVER" diff --git a/src/upgradeIntegrationTest/resources/pack.mcmeta b/src/upgradeIntegrationTest/resources/pack.mcmeta index 3eada7b..07e4060 100644 --- a/src/upgradeIntegrationTest/resources/pack.mcmeta +++ b/src/upgradeIntegrationTest/resources/pack.mcmeta @@ -2,7 +2,7 @@ "pack": { "description": "Sky's Grass Slabs build-only upgrade verification", "min_format": [101, 1], - "max_format": 107, - "min_format": [107, 1] + "max_format": 121, + "min_format": 121 } } From 315115974f5ffb3ab3d4d5399d7ed07778c24832 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Sun, 20 Sep 2026 14:35:49 +0100 Subject: [PATCH 2/2] Correct partial slab face culling --- CHANGELOG.md | 2 ++ docs/RELEASE-1.1.2.2603001.md | 3 +++ .../models/block/dirt_slab_snow.json | 2 +- .../models/block/dirt_slab_top_snow.json | 2 +- .../models/block/grass_slab.json | 2 +- .../models/block/grass_slab_snow.json | 2 +- .../models/block/grass_slab_top.json | 2 +- .../models/block/grass_slab_top_snow.json | 2 +- .../models/block/path_slab.json | 2 +- .../models/block/path_slab_top.json | 2 +- .../skysgrassslabs/ResourceContractTest.java | 27 +++++++++++++++++++ 11 files changed, 40 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b9829c..fd38986 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - Preserved all blocks, recipes, settings and supported world upgrades. - Updated shovel handling, bonemeal growth, world generation and data files for Minecraft 26.3. +- Corrected grass, snowy dirt and path slab models so their exposed inner + surfaces remain visible beside blocks. ## 1.1.2.2602001 - Minecraft 26.2 diff --git a/docs/RELEASE-1.1.2.2603001.md b/docs/RELEASE-1.1.2.2603001.md index 6d1bc39..6915560 100644 --- a/docs/RELEASE-1.1.2.2603001.md +++ b/docs/RELEASE-1.1.2.2603001.md @@ -4,6 +4,9 @@ This release brings the complete Sky's Grass Slabs feature set to Minecraft 26.3 and Forge 66. Dirt, grass and path slabs, turf, grass spreading, shovel flattening and terrain smoothing retain their established behaviour. +Slab surfaces remain visible when another block is placed above a bottom slab +or below a top slab. The correction also covers snowy dirt and path slabs. + Existing Sky's Grass Slabs worlds and the supported older slab migrations remain compatible. Back up an existing world before changing its Minecraft or Forge version. diff --git a/src/main/resources/assets/skysgrassslabs/models/block/dirt_slab_snow.json b/src/main/resources/assets/skysgrassslabs/models/block/dirt_slab_snow.json index 6339960..cba7658 100644 --- a/src/main/resources/assets/skysgrassslabs/models/block/dirt_slab_snow.json +++ b/src/main/resources/assets/skysgrassslabs/models/block/dirt_slab_snow.json @@ -10,7 +10,7 @@ "from": [0, 0, 0], "to": [16, 8, 16], "faces": { "down": { "uv": [0, 0, 16, 16], "texture": "#bottom", "cullface": "down" }, - "up": { "uv": [0, 0, 16, 16], "texture": "#top", "cullface": "up" }, + "up": { "uv": [0, 0, 16, 16], "texture": "#top" }, "north": { "uv": [0, 0, 16, 8], "texture": "#side", "cullface": "north" }, "south": { "uv": [0, 0, 16, 8], "texture": "#side", "cullface": "south" }, "west": { "uv": [0, 0, 16, 8], "texture": "#side", "cullface": "west" }, diff --git a/src/main/resources/assets/skysgrassslabs/models/block/dirt_slab_top_snow.json b/src/main/resources/assets/skysgrassslabs/models/block/dirt_slab_top_snow.json index 7150087..33e32bf 100644 --- a/src/main/resources/assets/skysgrassslabs/models/block/dirt_slab_top_snow.json +++ b/src/main/resources/assets/skysgrassslabs/models/block/dirt_slab_top_snow.json @@ -9,7 +9,7 @@ "elements": [{ "from": [0, 8, 0], "to": [16, 16, 16], "faces": { - "down": { "uv": [0, 0, 16, 16], "texture": "#bottom", "cullface": "down" }, + "down": { "uv": [0, 0, 16, 16], "texture": "#bottom" }, "up": { "uv": [0, 0, 16, 16], "texture": "#top", "cullface": "up" }, "north": { "uv": [0, 0, 16, 8], "texture": "#side", "cullface": "north" }, "south": { "uv": [0, 0, 16, 8], "texture": "#side", "cullface": "south" }, diff --git a/src/main/resources/assets/skysgrassslabs/models/block/grass_slab.json b/src/main/resources/assets/skysgrassslabs/models/block/grass_slab.json index 7d4b9a2..60d0b56 100644 --- a/src/main/resources/assets/skysgrassslabs/models/block/grass_slab.json +++ b/src/main/resources/assets/skysgrassslabs/models/block/grass_slab.json @@ -13,7 +13,7 @@ "from": [0, 0, 0], "to": [16, 8, 16], "faces": { "down": { "uv": [0, 0, 16, 16], "texture": "#bottom", "cullface": "down" }, - "up": { "uv": [0, 0, 16, 16], "texture": "#top", "cullface": "up", "tintindex": 0 }, + "up": { "uv": [0, 0, 16, 16], "texture": "#top", "tintindex": 0 }, "north": { "uv": [0, 0, 16, 8], "texture": "#side", "cullface": "north" }, "south": { "uv": [0, 0, 16, 8], "texture": "#side", "cullface": "south" }, "west": { "uv": [0, 0, 16, 8], "texture": "#side", "cullface": "west" }, diff --git a/src/main/resources/assets/skysgrassslabs/models/block/grass_slab_snow.json b/src/main/resources/assets/skysgrassslabs/models/block/grass_slab_snow.json index a56e0e4..9759d30 100644 --- a/src/main/resources/assets/skysgrassslabs/models/block/grass_slab_snow.json +++ b/src/main/resources/assets/skysgrassslabs/models/block/grass_slab_snow.json @@ -6,7 +6,7 @@ "from": [0, 0, 0], "to": [16, 8, 16], "faces": { "down": { "uv": [0, 0, 16, 16], "texture": "#bottom", "cullface": "down" }, - "up": { "uv": [0, 0, 16, 16], "texture": "#top", "cullface": "up" }, + "up": { "uv": [0, 0, 16, 16], "texture": "#top" }, "north": { "uv": [0, 0, 16, 8], "texture": "#side", "cullface": "north" }, "south": { "uv": [0, 0, 16, 8], "texture": "#side", "cullface": "south" }, "west": { "uv": [0, 0, 16, 8], "texture": "#side", "cullface": "west" }, diff --git a/src/main/resources/assets/skysgrassslabs/models/block/grass_slab_top.json b/src/main/resources/assets/skysgrassslabs/models/block/grass_slab_top.json index 0a436d3..f80a161 100644 --- a/src/main/resources/assets/skysgrassslabs/models/block/grass_slab_top.json +++ b/src/main/resources/assets/skysgrassslabs/models/block/grass_slab_top.json @@ -12,7 +12,7 @@ { "from": [0, 8, 0], "to": [16, 16, 16], "faces": { - "down": { "uv": [0, 0, 16, 16], "texture": "#bottom", "cullface": "down" }, + "down": { "uv": [0, 0, 16, 16], "texture": "#bottom" }, "up": { "uv": [0, 0, 16, 16], "texture": "#top", "cullface": "up", "tintindex": 0 }, "north": { "uv": [0, 0, 16, 8], "texture": "#side", "cullface": "north" }, "south": { "uv": [0, 0, 16, 8], "texture": "#side", "cullface": "south" }, diff --git a/src/main/resources/assets/skysgrassslabs/models/block/grass_slab_top_snow.json b/src/main/resources/assets/skysgrassslabs/models/block/grass_slab_top_snow.json index e514c0f..03537ba 100644 --- a/src/main/resources/assets/skysgrassslabs/models/block/grass_slab_top_snow.json +++ b/src/main/resources/assets/skysgrassslabs/models/block/grass_slab_top_snow.json @@ -5,7 +5,7 @@ "elements": [{ "from": [0, 8, 0], "to": [16, 16, 16], "faces": { - "down": { "uv": [0, 0, 16, 16], "texture": "#bottom", "cullface": "down" }, + "down": { "uv": [0, 0, 16, 16], "texture": "#bottom" }, "up": { "uv": [0, 0, 16, 16], "texture": "#top", "cullface": "up" }, "north": { "uv": [0, 0, 16, 8], "texture": "#side", "cullface": "north" }, "south": { "uv": [0, 0, 16, 8], "texture": "#side", "cullface": "south" }, diff --git a/src/main/resources/assets/skysgrassslabs/models/block/path_slab.json b/src/main/resources/assets/skysgrassslabs/models/block/path_slab.json index 87c51d8..9ae20fe 100644 --- a/src/main/resources/assets/skysgrassslabs/models/block/path_slab.json +++ b/src/main/resources/assets/skysgrassslabs/models/block/path_slab.json @@ -5,7 +5,7 @@ "from": [0, 0, 0], "to": [16, 7, 16], "faces": { "down": { "uv": [0, 0, 16, 16], "texture": "#bottom", "cullface": "down" }, - "up": { "uv": [0, 0, 16, 16], "texture": "#top", "cullface": "up" }, + "up": { "uv": [0, 0, 16, 16], "texture": "#top" }, "north": { "uv": [0, 1, 16, 8], "texture": "#side", "cullface": "north" }, "south": { "uv": [0, 1, 16, 8], "texture": "#side", "cullface": "south" }, "west": { "uv": [0, 1, 16, 8], "texture": "#side", "cullface": "west" }, diff --git a/src/main/resources/assets/skysgrassslabs/models/block/path_slab_top.json b/src/main/resources/assets/skysgrassslabs/models/block/path_slab_top.json index 3a98eed..7f45a25 100644 --- a/src/main/resources/assets/skysgrassslabs/models/block/path_slab_top.json +++ b/src/main/resources/assets/skysgrassslabs/models/block/path_slab_top.json @@ -4,7 +4,7 @@ "elements": [{ "from": [0, 8, 0], "to": [16, 15, 16], "faces": { - "down": { "uv": [0, 0, 16, 16], "texture": "#bottom", "cullface": "down" }, + "down": { "uv": [0, 0, 16, 16], "texture": "#bottom" }, "up": { "uv": [0, 0, 16, 16], "texture": "#top", "cullface": "up" }, "north": { "uv": [0, 1, 16, 8], "texture": "#side", "cullface": "north" }, "south": { "uv": [0, 1, 16, 8], "texture": "#side", "cullface": "south" }, diff --git a/src/test/java/zone/moddev/mc/skysgrassslabs/ResourceContractTest.java b/src/test/java/zone/moddev/mc/skysgrassslabs/ResourceContractTest.java index fcd0e74..a3c1cf8 100644 --- a/src/test/java/zone/moddev/mc/skysgrassslabs/ResourceContractTest.java +++ b/src/test/java/zone/moddev/mc/skysgrassslabs/ResourceContractTest.java @@ -82,6 +82,25 @@ public void grassSlabUsesVanillaGrassCutoutLayer() throws Exception { } } + @Test + public void partialSlabModelsKeepTheirInteriorHorizontalFacesVisible() throws Exception { + for (String modelName : new String[] {"grass_slab", "grass_slab_snow", + "dirt_slab_snow", "path_slab"}) { + var faces = modelFaces(modelName); + assertFalse(modelName, faces.getAsJsonObject("up").has("cullface")); + assertEquals(modelName, "down", + faces.getAsJsonObject("down").get("cullface").getAsString()); + } + + for (String modelName : new String[] {"grass_slab_top", "grass_slab_top_snow", + "dirt_slab_top_snow", "path_slab_top"}) { + var faces = modelFaces(modelName); + assertFalse(modelName, faces.getAsJsonObject("down").has("cullface")); + assertEquals(modelName, "up", + faces.getAsJsonObject("up").get("cullface").getAsString()); + } + } + @Test public void snowyGrassSlabModelsUseUntintedSnowCaps() throws Exception { for (String modelName : new String[] {"grass_slab_snow", "grass_slab_top_snow"}) { @@ -128,4 +147,12 @@ private static void assertParses(Path path) { throw new AssertionError("Invalid JSON: " + path, exception); } } + + private static com.google.gson.JsonObject modelFaces(String modelName) throws IOException { + return JsonParser.parseString(Files.readString(Path.of( + "src/main/resources/assets/skysgrassslabs/models/block/" + + modelName + ".json"))) + .getAsJsonObject().getAsJsonArray("elements").get(0).getAsJsonObject() + .getAsJsonObject("faces"); + } }