Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,9 @@ jobs:
if-no-files-found: error
retention-days: 30
path: |
build/libs/SkysBuildingPieces-0.3.9.2603001.jar
build/libs/SkysBuildingPieces-0.3.9.2603001-sources.jar
build/libs/SkysBuildingPieces-0.3.9.2603001-javadoc.jar
build/libs/SkysBuildingPieces-0.3.10.2603001.jar
build/libs/SkysBuildingPieces-0.3.10.2603001-sources.jar
build/libs/SkysBuildingPieces-0.3.10.2603001-javadoc.jar
build/release/SHA256SUMS
CHANGELOG.md

Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## 0.3.10.2603001

- Let grass pieces spread and decay naturally, including beneath solid cover.
- Improve snow caps and cover the exposed grass below snowy pieces.
- Keep snow pieces when dug by hand.
- Let wooden pieces fuel furnaces, smokers and blast furnaces, scaled to the size of the piece.
- Fix a client crash when block-breaking or sprint particles touch grass beneath snowy pieces.
- Separate different crafting results in the recipe book and retain their unlocks.


## 0.3.9.2603001

- Removed duplicate grass and dirt slab recipes when Sky's Grass Slabs is installed.
Expand Down
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ block above keeps a supporting post. Matching glass walls form a continuous
run, with borders at posts, exposed ends and colour changes.

Dirt and grass steps and corners are included too. Grass follows biome colours,
spreads and decays much like vanilla grass. Plants need a complete upper face.
spreads and decays much like vanilla grass. Plants need a complete upper face. Snowy steps and corners also cover the
exposed grass below them; removing or thawing the piece restores its normal
appearance.
Use a shovel on an uncovered dirt or grass step or corner to turn it into a
matching path piece. Its footprint stays the same, with a one-pixel lower top.
Flattening a grass piece also turns an ordinary grass block directly beneath
Expand All @@ -46,10 +48,18 @@ still open.

Craft pieces from matching full blocks, slabs and steps. For example, three
full blocks in a row make six slabs, and two matching slabs placed diagonally
make four steps. Existing vanilla recipes stay available.
make four steps. Existing vanilla recipes stay available. Each result has its own recipe-book
button, with alternatives grouped only when they make the same item.

For snow slabs, place two snow blocks diagonally to make four slabs. Three
snow blocks in a row still make vanilla snow layers. Snow pieces can be
recovered by hand; a shovel mines them faster.
You can also rebuild larger pieces: stack two matching corners in the crafting
grid for one step, or two matching steps for one slab.

Wooden slabs, steps and corners can fuel a furnace. Smaller pieces burn for
less time, so cutting a plank doesn't create extra fuel.

The [recipe and placement guide](docs/GAMEPLAY.md) has the full patterns,
quantities and exceptions, including the separate dirt vertical slab recipe
when Grass Slabs isn't installed.
Expand All @@ -63,7 +73,7 @@ server.
You can also add:

- [Sky's Grass Slabs](https://github.com/MinecraftModDevelopmentMods/SkysGrassSlabs)
version 1.2.0.2603001 or later for horizontal dirt and grass slabs, paths and turf.
version 1.2.1.2603001 or later for horizontal dirt and grass slabs, paths and turf.
- [The Biomes O' Plenty add-on](https://github.com/MinecraftModDevelopmentMods/SkysBuildingPieces-BiomesOPlenty-Addon)
for pieces made from BOP woods, stones and gem blocks.
- [Sky's Terrain Smoother](https://github.com/MinecraftModDevelopmentMods/SkysTerrainSmoother)
Expand Down
8 changes: 8 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -873,3 +873,11 @@ apply from: 'gradle/forge-client-control.gradle'
apply from: 'gradle/native-compatibility.gradle'
apply from: 'gradle/forge-server-control.gradle'
apply from: 'gradle/native-unit-launcher.gradle'

apply from: 'gradle/recipe-resource-sync.gradle'

tasks.register('verifyCraftingResources', Exec) {
group = 'verification'
commandLine providers.gradleProperty('pythonExecutable').getOrElse('python'), 'tools/test_recipe_ownership.py'
}
tasks.named('check') { dependsOn tasks.named('verifyCraftingResources') }
12 changes: 6 additions & 6 deletions docs/BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ and exclude test classes. The generated output also declares the same mixins as
the packaged jar, so save recovery works in development runs.

- `runClient` and `runServer` load Building Pieces on its own.
- `runGrassSlabsClient` and `runGrassSlabsServer` add the coordinated Grass Slabs
candidate recorded in `gradle/grass-slabs-release.properties`.
- `runGrassSlabsClient` and `runGrassSlabsServer` add the Grass Slabs release
recorded in `gradle/grass-slabs-release.properties`.
- `runMineralogyClient` and `runMineralogyServer` add the optional Mineralogy and
OreSpawn jars recorded in `gradle/mineralogy-runtime.properties`.

The Grass Slabs pin currently names a source candidate, not a public release.
Build that exact commit in the sibling `SkysGrassSlabs263/SkysGrassSlabs` checkout,
or pass `-PgrassSlabsMainJar=<jar>`. The jar must match its pinned hash. CI builds the pinned commit before testing the optional
integration; it can run after that commit is available in the upstream repository.
Build that exact Grass Slabs commit in the sibling
`SkysGrassSlabs263/SkysGrassSlabs` checkout, or pass
`-PgrassSlabsMainJar=<jar>`. The jar must match its pinned hash.
CI builds the same commit before testing the optional integration.
Building Pieces does not bundle any Grass Slabs classes or require it to play.

Optional Mineralogy/OreSpawn jars also need their exact recorded hashes. Each
Expand Down
7 changes: 6 additions & 1 deletion docs/INTEGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ mod construction, before registry events; permanent palette slots must never be
The JSON-array overload of `registerCatalogue` accepts resolved material and
palette definitions. Use it when a native mod can disable some shapes, without
changing the permanent piece palettes. A material can set
`cookingFuel: false` when its wood cannot be used as furnace fuel, as with
BOP hellbark. Fuel is separate from flammability. Other wooden materials use
Minecraft's plank fuel rules, scaled to the piece's size.

A material can set
`fullBlockStepRecipe: true` to cut three diagonal full blocks into twelve
steps instead of using the usual two-slab recipe.

Expand All @@ -17,7 +22,7 @@ west; corners use those directions for NW, NE, SE and SW respectively.

Sky's Terrain Smoother uses this lookup without depending on palette internals.
Building Pieces never generates terrain itself. It optionally joins Grass
Slabs' grass-form integration, using 1.2.0.2603001 or later on Minecraft 26.3.
Slabs' grass-form integration, using 1.2.1.2603001 or later on Minecraft 26.3.
It works without either Grass Slabs or Terrain Smoother installed.

Mineralogy is supported directly. Its presence adds 35 fixed rock-piece
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ release_enabled=true
curseforge_project_id=1754162
mod_name=Sky's Building Pieces
mod_license=LGPL-2.1-only
mod_version=0.3.9.2603001
mod_version=0.3.10.2603001
mod_group=zone.moddev.mc.skysbuildingpieces
mod_authors=SkyBlade1978
mod_description=Extra building shapes for vanilla materials, with built-in Mineralogy support when installed. No world generation.
10 changes: 5 additions & 5 deletions gradle/grass-slabs-release.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ def lock = new Properties()
file('gradle/grass-slabs-release.properties').withInputStream { lock.load(it) }
def configureVerification = project.ext.configureMineralogyVerificationRun
if (lock.coordinate != "zone.moddev.mc.skysgrassslabs:SkysGrassSlabs:${lock.version}" ||
lock.kind != 'local-candidate' || !(lock.sha256 ==~ /[A-F0-9]{64}/) ||
!(lock.kind in ['local-candidate', 'release']) || !(lock.sha256 ==~ /[A-F0-9]{64}/) ||
!(lock.getProperty('development.sha256') ==~ /[A-F0-9]{64}/)) {
throw new GradleException('The coordinated Grass Slabs dependency needs exact candidate checksums')
throw new GradleException('The Grass Slabs dependency needs a valid source kind and exact checksums')
}

def sibling = "../../SkysGrassSlabs263/SkysGrassSlabs"
Expand All @@ -23,7 +23,7 @@ def developmentJar = layout.projectDirectory.file(providers.gradleProperty('gras

def verifyRelease = tasks.register('verifyGrassSlabsRelease') {
group = 'verification'
description = 'Checks both exact Grass Slabs candidate jars used by optional family tests.'
description = 'Checks both exact Grass Slabs jars used by optional family tests.'
inputs.file pinnedJar
inputs.file developmentJar
inputs.file 'gradle/grass-slabs-release.properties'
Expand All @@ -33,15 +33,15 @@ def verifyRelease = tasks.register('verifyGrassSlabsRelease') {
String actual = MessageDigest.getInstance('SHA-256').digest(Files.readAllBytes(source.toPath()))
.encodeHex().toString().toUpperCase(Locale.ROOT)
if (actual != entry[1]) {
throw new GradleException('Grass Slabs does not match its pinned candidate checksum: ' + source.name)
throw new GradleException('Grass Slabs does not match its pinned checksum: ' + source.name)
}
new ZipFile(source).withCloseable { archive ->
def descriptor = archive.getEntry('META-INF/mods.toml')
if (descriptor == null) throw new GradleException('Grass Slabs has no Forge 66 metadata')
String metadata = archive.getInputStream(descriptor).getText('UTF-8')
if (!(metadata =~ /(?m)^\s*modId\s*=\s*"skysgrassslabs"\s*$/) ||
!(metadata =~ /(?m)^\s*version\s*=\s*"${java.util.regex.Pattern.quote(lock.version)}"\s*$/)) {
throw new GradleException('Grass Slabs has unexpected candidate metadata')
throw new GradleException('Grass Slabs has unexpected version or mod metadata')
}
}
}
Expand Down
14 changes: 7 additions & 7 deletions gradle/grass-slabs-release.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Coordinated Grass Slabs candidate for Forge 26.3.
kind=local-candidate
version=1.2.0.2603001
coordinate=zone.moddev.mc.skysgrassslabs:SkysGrassSlabs:1.2.0.2603001
sha256=20AE5DC12C97E8DC1D348282BE50697909E98BBCE8C3BD40E4CF910E7D85F7D9
development.sha256=20AE5DC12C97E8DC1D348282BE50697909E98BBCE8C3BD40E4CF910E7D85F7D9
source.commit=014f8d16f0a5ef83c4cc236d37590afac56a6087
# Grass Slabs release used for Forge 26.3 integration.
kind=release
version=1.2.1.2603001
coordinate=zone.moddev.mc.skysgrassslabs:SkysGrassSlabs:1.2.1.2603001
sha256=55E417284B1F5982E88EF4B2B69F8B766A7EA473F3AE30DE9CE3AF8E2D988DFA
development.sha256=55E417284B1F5982E88EF4B2B69F8B766A7EA473F3AE30DE9CE3AF8E2D988DFA
source.commit=e264974ba2e023a8d1c38753ef88824afd1c72ff
16 changes: 15 additions & 1 deletion gradle/mineralogy-runs.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@ import java.nio.file.Files
// These are optional development mods, never compile or production dependencies.
def runtimeLock = new Properties()
file('gradle/mineralogy-runtime.properties').withInputStream { runtimeLock.load(it) }
def retainedRuntimeJars = ['mineralogy', 'orespawn'].collectEntries { mod ->
File siblingJar = file(runtimeLock.getProperty(mod + '.path'))
String checksum = runtimeLock.getProperty(mod + '.sha256')
[(mod): file(".gradle/qualification-dependencies/${checksum}/${siblingJar.name}")]
}

def runtimeSources = ['mineralogy', 'orespawn'].collectEntries { mod ->
File siblingJar = file(runtimeLock.getProperty(mod + '.path'))
File retainedJar = file('.gradle/qualification-dependencies/' + siblingJar.name)
File retainedJar = retainedRuntimeJars[mod]
// Sibling builds can change during other work. A retained copy still has to
// pass the same checksum check before it can enter a development profile.
[(mod): file(providers.gradleProperty(mod + 'RuntimeJar')
Expand Down Expand Up @@ -59,6 +65,14 @@ def installRuntimeMods = {
throw new GradleException("The ordinary Mineralogy profile must not contain test mods: ${candidate}")
}
}
runtimeSources.each { mod, source ->
File retained = retainedRuntimeJars[mod]
if (source.canonicalFile != retained.canonicalFile) {
// Keep this verified build when another project rebuilds the sibling jar.
Files.createDirectories(retained.parentFile.toPath())
Files.copy(source.toPath(), retained.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING)
}
}
// Copy only the declared jars. Never sync or clear a player's mods, config or saves.
copy {
from runtimeSources.values(), extraMods
Expand Down
7 changes: 6 additions & 1 deletion gradle/native-bootstrap.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,21 @@ def compileBootstrap = tasks.register('compileNativeBootstrapProbe', JavaCompile
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/PersistenceRegistrationChecks.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/NativeProbeItems.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/GameplayChecks.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/FuelChecks.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/PathChecks.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/SharedGrassChecks.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/RecombinationChecks.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/RecipeBookChecks.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/RecipeUniquenessChecks.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/PresentationChecks.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/GlassModelProbe.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/ClientProbe.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/ConfigScreenChecks.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/ClientStatus.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/ProbeProxy.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/RecipePreviewModels.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/RecipeBookGroupChecks.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/SnowCoverClientChecks.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/MineralogyChecks.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/RecipeChecks.java')
source file('src/integrationTest/java/zone/moddev/mc/skysbuildingpieces/probe/NativeRecipeProbe.java')
Expand Down Expand Up @@ -257,12 +261,13 @@ def clientPhases = [:]
dependsOn phase == 'client-fresh' ? prepareClient : clientPhases['client-fresh']
workingDir clientDirectory
systemProperty 'skysbuildingpieces.bootstrapPhase', phase
args '--accessToken', '0'
project.ext.configureNativeBootstrapRun(delegate, 'runClient')
doLast {
logger.lifecycle(providers.exec {
commandLine providers.gradleProperty('pythonExecutable').getOrElse('python'),
file('tools/native_client_log.py'), '--directory', clientDirectory.get().asFile,
'--phase', phase
'--phase', phase, '--offline-client'
}.standardOutput.asText.get().trim())
}
}
Expand Down
65 changes: 65 additions & 0 deletions gradle/recipe-resource-sync.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Keep removed recipes out of packaged resources and existing Eclipse outputs.
def recipeOwners = project.mod_id == 'skysbuildingpiecesbop'
? ['skysbuildingpieces', 'skysbuildingpiecesbop'] : [project.mod_id]
def recipeFolders = recipeOwners.collectMany { owner ->
["data/${owner}/recipe", "data/${owner}/advancement/recipes"]
}

def insideProject = { File directory ->
File resolved = directory.canonicalFile
if (!resolved.toPath().startsWith(projectDir.canonicalFile.toPath())
|| resolved == projectDir.canonicalFile) {
throw new GradleException("Recipe output is outside this checkout: ${resolved}")
}
resolved
}

def recipeFiles = { File root ->
Set<String> files = new TreeSet<>()
recipeFolders.each { relative ->
File folder = new File(root, relative)
fileTree(folder) { include '**/*.json' }.files.each { path ->
files.add(relative + '/' + folder.toPath().relativize(path.toPath()).toString().replace('\\', '/'))
}
}
files
}

tasks.named('processResources') {
doFirst {
File output = insideProject(destinationDir)
recipeFolders.each { relative ->
project.delete(insideProject(new File(output, relative)))
}
}
}

tasks.named('prepareEclipseResources') {
doLast {
File eclipseOutput = insideProject(file('bin/main'))
recipeFolders.each { relative ->
project.sync {
from(layout.buildDirectory.dir("resources/main/${relative}"))
into(insideProject(new File(eclipseOutput, relative)))
}
}
}
}

def verifyRecipeResourceOutputs = tasks.register('verifyRecipeResourceOutputs') {
group = 'verification'
description = 'Checks that processed and Eclipse recipes match the current source resources.'
dependsOn tasks.named('processResources'), tasks.named('prepareEclipseResources')
doLast {
Set<String> expected = new TreeSet<>()
sourceSets.main.resources.srcDirs.each { root -> expected.addAll(recipeFiles(root)) }
[layout.buildDirectory.dir('resources/main').get().asFile, file('bin/main')].each { output ->
Set<String> actual = recipeFiles(output)
if (actual != expected) {
throw new GradleException("Recipe output mismatch in ${output}: "
+ "missing=${expected - actual}, stale=${actual - expected}")
}
}
}
}
tasks.named('check') { dependsOn verifyRecipeResourceOutputs }
2 changes: 1 addition & 1 deletion gradle/release.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ tasks.register('verifyReleaseBundleContract') {
group = 'verification'
dependsOn tasks.named('writeReleaseChecksums')
doLast {
File bundle = layout.buildDirectory.dir('release-bundle-test').get().asFile
File bundle = layout.buildDirectory.dir("release-bundle-test/${project.version}").get().asFile
List<String> filenames = releaseFiles.get().collect { it.toString() }
copy {
from layout.buildDirectory.dir('libs')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ private void audit(MinecraftServer server, DeferredAudit pending) {
int recipes = 0;
int stacks = 0;

if (pending == null && (phase.equals("fresh") || phase.equals("reload") || phase.startsWith("client"))) {
FuelChecks.run(world);
}

if (phase.equals("water")) {
WaterloggingChecks.run(world);
} else if (phase.equals("staging")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ public void tick(TickEvent.ClientTickEvent.Post event) {
return;
}
RecipePreviewModels.check(minecraft, expectedRecipes);
RecipeBookGroupChecks.run(minecraft, expectedRecipes);
SnowCoverClientChecks.run(minecraft);
// Item components are bound when the world is ready, after the first menu bake.
checkCreativeEntries();
colours(minecraft);
Expand Down
Loading
Loading