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..fd38986 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # 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. +- Corrected grass, snowy dirt and path slab models so their exposed inner + surfaces remain visible beside blocks. + ## 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 b5f7fb5..86aeb5e 100644 Binary files a/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar and b/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.jar differ diff --git a/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.patch b/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.patch index b0c92c5..5a947f4 100644 --- a/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.patch +++ b/ci-fixtures/tools/minecraft-mavenizer-0.5.21-orespawn-compat.patch @@ -1,7 +1,7 @@ -From 96468d9931e7f1448d9fb00f13ec0a6559ee0054 Mon Sep 17 00:00:00 2001 -From: OreSpawn Build Fixture -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..6915560 --- /dev/null +++ b/docs/RELEASE-1.1.2.2603001.md @@ -0,0 +1,15 @@ +# 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. + +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. + +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/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/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..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"}) { @@ -104,9 +123,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 +134,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")); @@ -130,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"); + } } 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 0000000..66a6a7d Binary files /dev/null and b/src/test/resources/fixtures/skysgrassslabs-26.2-forward-world.zip differ 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 } }