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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/deploy-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,11 @@ jobs:
with:
curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }}
curseforge-id: ${{ needs.preflight.outputs.curseforge_project_id }}
# A timeout can follow an accepted upload. Check the file before retrying.
curseforge-retry-attempts: 1
curseforge-dependencies: |
1677588(required)
1754162(required)
name: Sky's Terrain Smoother ${{ needs.preflight.outputs.release_version }} for Minecraft ${{ needs.preflight.outputs.minecraft_version }} (${{ needs.preflight.outputs.loader_display }})
version: ${{ needs.preflight.outputs.release_version }}
version-type: ${{ inputs.curseforge_release_level }}
Expand Down
17 changes: 14 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,20 @@

## 0.1.0.112021

- Added Minecraft 1.12.2 support for surface and cave smoothing.
- Kept all three levels, matching sand caps and existing-world protections.
- Retained optional Mineralogy support without adding duplicate rock pieces.
- Added ingredient-based recipe unlocks, including slab recombination.

- Added Minecraft 1.12.2 support for new surface terrain and cave floors.
- Made level 3 the default for new configurations. Existing choices are kept.
- Used Building Pieces' built-in Mineralogy steps and corners at levels 2 and 3;
no separate Mineralogy add-on is needed.
- Kept exposed grass beneath steps and corners, including snowy transitions.
- Improved narrow ledges without recreating full-block jumps. Fitting steps and
corners can still smooth mixed uphill and downhill edges.
- Let thin snow, grass and flowers give way to valid transitions in new terrain.
Deeper snow, trees, crops and existing saved chunks stay untouched.
- Added the Mods Config screen, help text and separate Mineralogy test profiles.
- Updated the dependency pins to released Grass Slabs 1.1.2.112021 and
Building Pieces 0.3.8.112021, including the Eclipse development setup.

## 0.1.0.110021

Expand Down
41 changes: 29 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,21 @@ sandstone, sand and hardened clay.

Set `worldgen.smoothingLevel` in `config/skysterrainsmoother.cfg`:

1. **Slabs** — half-block transitions.
2. **Slabs and steps** — adds pieces covering half a slab's footprint.
3. **Slabs, steps and corners** — also uses pieces covering a quarter of a
1. **Slabs** - half-block transitions.
2. **Slabs and steps** - adds pieces covering half a slab's footprint.
3. **Slabs, steps and corners** - also uses pieces covering a quarter of a
slab's footprint.

Every smoothing piece is half a block tall. If a material doesn't have steps
or corners, it still uses its slab at higher levels.
or corners, it uses its slab at higher levels wherever a slab fits safely.

Narrow mountain ledges keep their downhill edge at its original height, rather
than gaining a row of slabs that recreates a full-block step. Wider terraces
still get transitions. At levels 2 and 3, the engine keeps a fitting uphill step
or corner even when a whole slab would raise the downhill edge.

A single layer of snow doesn't block an otherwise valid transition. Deeper
snow, trees, crops and occupied blocks stay untouched.

Only new, dry terrain is smoothed. Existing chunks, underwater floors and cave
ceilings stay unchanged. Cave passages need three clear blocks above the floor,
Expand All @@ -29,9 +37,9 @@ blocks in a row make six slabs, and two slabs side by side make a full block.
Like sand blocks, the slabs fall when unsupported. Sand uses slabs at every
smoothing level.

Mineralogy is supported without another add-on. When it's installed, available
natural rock slabs are used by default. It doesn't get new steps or corners
from this mod, and disabled slab types are skipped.
Mineralogy is supported without another add-on. When it's installed, the
smoother uses its natural rock slabs and the matching steps and corners
included in Building Pieces. Disabled native slab types are skipped.

Ores, gravel, wood and decorative stone aren't smoothing materials.

Expand All @@ -42,21 +50,30 @@ For BOP grass and soils, add the

For **Minecraft 1.12.2**, use **Forge 14.23.5.2859** and **Java 8**, with:

- Sky's Grass Slabs **1.1.0.112021**.
- Sky's Building Pieces **0.3.6.112021**.
- Sky's Grass Slabs **1.1.2.112021**.
- Sky's Building Pieces **0.3.8.112021**.
- Sky's Terrain Smoother **0.1.0.112021**.

Install all three main jars on both the client and server.

Smoothing starts at level 1. Stop the game or server before editing the
configuration, then restart. You can turn smoothing off or disable Mineralogy
support; see [configuration](docs/CONFIGURATION.md).
New configurations start at level 3. Existing saved choices are kept.
Select the mod in **Mods > Config** to choose a
level, turn smoothing off or disable Mineralogy support, then restart Minecraft.
For a dedicated server, edit its configuration file and restart the server.
See [configuration](docs/CONFIGURATION.md).

While installed, Terrain Smoother handles grass smoothing instead of Grass Slabs.
Turning its master switch off stops both passes. Grass Slabs' own
`worldgen.generateGrassSlabs` setting still decides whether grass is included.
Removing Terrain Smoother restores Grass Slabs' standalone generation.

## Mineralogy steps and corners

Building Pieces 0.3.7 or later includes Mineralogy rock steps and corners.
Install Mineralogy alongside the usual Sky mods; no separate Mineralogy
add-on is needed. Level 1 uses native slabs, level 2 also uses steps and
level 3 also uses corners. Your Mineralogy support setting still applies.

## Existing worlds

Back up worlds before changing their mods. Turning smoothing off doesn't remove
Expand Down
99 changes: 93 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,20 @@ tasks.withType(JavaCompile).configureEach {

def grassSlabsDirectory = file(providers.gradleProperty('grassSlabsDirectory').getOrElse('../..' + '/SkysGrassSlabs112/SkysGrassSlabs'))
def buildingPiecesDirectory = file(providers.gradleProperty('buildingPiecesDirectory').getOrElse('../..' + '/SkysBuildingPieces112/SkysBuildingPieces'))
def grassSlabsDevelopmentJar = new File(grassSlabsDirectory, 'build/libs-dev/SkysGrassSlabs-1.1.0.112021-deobf.jar')
def contentLock=new Properties()
file('gradle/content-dependencies.properties').withInputStream { contentLock.load(it) }

def localGrassVersion = providers.gradleProperty('grassSlabsVersion')
if (localGrassVersion.isPresent() &&
(System.getenv('CI') != null || !providers.gradleProperty('grassSlabsDirectory').isPresent())) {
throw new GradleException('A local grass-version override needs an explicit directory and is not allowed in CI.')
}
def grassVersion = localGrassVersion.getOrElse(contentLock.getProperty('grass.version'))


def grassSlabsDevelopmentJar = new File(grassSlabsDirectory,
"build/libs-dev/SkysGrassSlabs-${grassVersion}-deobf.jar")

def localPiecesVersion = providers.gradleProperty('buildingPiecesCoreVersion')
if (localPiecesVersion.isPresent() &&
(System.getenv('CI') != null || !providers.gradleProperty('buildingPiecesDirectory').isPresent())) {
Expand All @@ -78,9 +88,14 @@ def verifyContentDependencies=tasks.register('verifyContentDependencies') {
[grass:grassSlabsDirectory,pieces:buildingPiecesDirectory].each { name,directory ->
Properties metadata=new Properties()
new File(directory,'gradle.properties').withInputStream { metadata.load(it) }
String expectedVersion = name == 'pieces' ? piecesVersion : contentLock.getProperty(name + '.version')
if(metadata.mod_version!=expectedVersion)
throw new GradleException('Content dependency version does not match its lock: '+name)
String expectedVersion = name == 'grass' ? grassVersion : name == 'pieces' ? piecesVersion : contentLock.getProperty(name + '.version')
if (metadata.mod_version != expectedVersion) {
String localHelp = name == 'pieces' && System.getenv('CI') == null ?
' For a local candidate, supply both -PbuildingPiecesDirectory=<checkout>' +
' and -PbuildingPiecesCoreVersion=<version>, then regenerate the Eclipse runs.' : ''
throw new GradleException("Content dependency version does not match its lock: ${name}" +
" (expected ${expectedVersion}, found ${metadata.mod_version})." + localHelp)
}
if(System.getenv('CI')!=null) {
Process git=new ProcessBuilder('git','-C',directory.path,'rev-parse','HEAD').start()
String sha=git.inputStream.getText('UTF-8').trim()
Expand Down Expand Up @@ -147,6 +162,7 @@ minecraft {
runs {
configureEach {
workingDir.convention layout.projectDirectory.dir(developmentRunDirectory)
environment 'MC_VERSION', project.minecraft_version.toString()
systemProperty 'forge.logging.console.level', 'debug'
systemProperty 'fml.coreMods.load', 'zone.moddev.mc.skysbuildingpieces.legacy.LoaderPlugin'
}
Expand Down Expand Up @@ -588,6 +604,7 @@ ext.releaseFiles = releaseFiles
ext.releaseJar = releaseJar
apply from: 'gradle/release.gradle'


// Keep the old entry point disabled until publication is configured.
tasks.register('publishRelease') {
doLast { throw new GradleException('Publication is disabled for the local beta.') }
Expand All @@ -597,8 +614,27 @@ idea {
module { downloadSources = true; downloadJavadoc = true }
}
eclipse {
classpath { downloadSources = true; downloadJavadoc = true }
synchronizationTasks 'genEclipseRuns'
classpath {
downloadSources = true
downloadJavadoc = true
file.whenMerged { classpath ->
// Eclipse copies these files on every build. Use Gradle's expanded metadata, never the template.
def resources = classpath.entries.findAll {
it instanceof org.gradle.plugins.ide.eclipse.model.SourceFolder &&
it.path in ['src/main/resources', 'build/resources/main']
}
// Keep one entry when Gradle merges an existing Eclipse classpath.
resources.drop(1).each { classpath.entries.remove(it) }
resources.take(1).each { entry ->
entry.path = 'build/resources/main'
}
}
}
synchronizationTasks 'processResources', 'genEclipseRuns'
}

tasks.named('eclipseClasspath') {
dependsOn tasks.named('processResources'), verifyContentDependencies
}

def prepareEclipseResources = tasks.register('prepareEclipseResources') {
Expand Down Expand Up @@ -626,6 +662,20 @@ def configureEclipseBuildship = tasks.register('configureEclipseBuildship') {
'gradle.user.home': gradle.gradleUserHomeDir.canonicalPath,
'override.workspace.settings': 'true'
].each { key, value -> preferences.setProperty(key, value) }
// Refreshes must use the same checkouts, without retaining an old candidate override.
List<String> arguments = preferences.getProperty('arguments', '').tokenize(' ')
arguments.removeAll {
it.startsWith('-PgrassSlabsDirectory=') || it.startsWith('-PgrassSlabsVersion=') ||
it.startsWith('-PbuildingPiecesDirectory=') ||
it.startsWith('-PbuildingPiecesCoreVersion=')
}
arguments.add('-PgrassSlabsDirectory=' + relativePath(grassSlabsDirectory))
if (localGrassVersion.isPresent()) arguments.add('-PgrassSlabsVersion=' + grassVersion)
arguments.add('-PbuildingPiecesDirectory=' + relativePath(buildingPiecesDirectory))
if (localPiecesVersion.isPresent()) {
arguments.add('-PbuildingPiecesCoreVersion=' + piecesVersion)
}
preferences.setProperty('arguments', arguments.join(' '))
preferencesFile.parentFile.mkdirs()
preferencesFile.withOutputStream { preferences.store(it, 'Generated Buildship configuration.') }
}
Expand All @@ -639,6 +689,7 @@ tasks.register('isolateEclipseProductionRuns') {
File launch = file(name)
if (!launch.isFile()) throw new GradleException("ForgeGradle did not generate ${name}")
String contents = launch.getText('UTF-8')
contents = contents.replace('${MC_VERSION}', project.minecraft_version.toString())
boolean production = name in ['runClient.launch', 'runServer.launch']
if (production && !contents.contains('org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE')) {
contents = contents.replace('</launchConfiguration>',
Expand Down Expand Up @@ -677,7 +728,36 @@ tasks.register('verifyEclipseProductionClasspath') {
if (file(prefs.getProperty('connection.gradle.user.home', '')).canonicalFile != gradle.gradleUserHomeDir.canonicalFile) {
throw new GradleException('Eclipse Buildship uses the wrong Gradle home')
}
List<String> arguments = prefs.getProperty('arguments', '').tokenize(' ')
if (!arguments.contains('-PgrassSlabsDirectory=' + relativePath(grassSlabsDirectory)) ||
!arguments.contains('-PbuildingPiecesDirectory=' + relativePath(buildingPiecesDirectory))) {
throw new GradleException('Eclipse Buildship lost the selected content checkouts')
}
List<String> overrides = arguments.findAll { it.startsWith('-PbuildingPiecesCoreVersion=') }
List<String> expectedOverrides = localPiecesVersion.isPresent() ?
['-PbuildingPiecesCoreVersion=' + piecesVersion] : []
if (overrides != expectedOverrides) {
throw new GradleException('Eclipse Buildship retained an incorrect Building Pieces version override')
}
File metadata = file('bin/main/mcmod.info')
def eclipseClasspath = new groovy.xml.XmlSlurper().parse(file('.classpath'))
def piecesLibraries = eclipseClasspath.classpathentry.findAll {
it.@kind == 'lib' && it.@path.text().tokenize('/\\').last().startsWith('SkysBuildingPieces-')
}*.@path*.text().collect { file(it).canonicalFile }
if (piecesLibraries != [buildingPiecesDevelopmentJar.canonicalFile]) {
throw new GradleException('Eclipse must use only the selected Building Pieces development jar')
}
def grassLibraries = eclipseClasspath.classpathentry.findAll {
it.@kind == 'lib' && it.@path.text().tokenize('/\\').last().startsWith('SkysGrassSlabs-')
}*.@path*.text().collect { file(it).canonicalFile }
if (grassLibraries != [grassSlabsDevelopmentJar.canonicalFile]) {
throw new GradleException('Eclipse must use only the pinned Grass Slabs development jar')
}
def resourceFolders = eclipseClasspath.classpathentry.findAll { it.@kind == 'src' }*.@path*.text()
if (resourceFolders.contains('src/main/resources') ||
resourceFolders.count { it == 'build/resources/main' } != 1) {
throw new GradleException('Eclipse must copy processed resources, not overwrite them with templates')
}
def parsed = new JsonSlurper().parseText(metadata.getText('UTF-8'))
if (parsed[0].version != project.mod_version || parsed[0].mcversion != project.minecraft_version) {
throw new GradleException('Eclipse output contains incorrect mcmod.info')
Expand Down Expand Up @@ -718,3 +798,10 @@ tasks.register('integrationClientReloadProcess', JavaExec) {
if(!marker.isFile() || !marker.text.contains('reload_complete=true')) throw new GradleException('Integrated reload client did not complete')
}
}

ext.configureMineralogyVerificationRun = configureFromForgeRun
ext.mineralogyProfileProbeId = 'skysterrainsmoother'
ext.mineralogyProfileAdditionalMods = files()
apply from: 'gradle/mineralogy-runs.gradle'

apply from: 'gradle/recipe-advancements.gradle'
9 changes: 6 additions & 3 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ TerrainSmoothingApi.registerMaterial(new TerrainMaterial(

`addShapes(materialId, steps, corners)` supplies missing forms on an existing
mapping. It cannot replace that mapping's slab or existing finer forms. A
Mineralogy add-on can therefore extend a built-in `mineralogy:<rock>` mapping
without replacing its native slab. Do not assume the mapping exists when the
material add-on can therefore extend an existing mapping without replacing
its native slab. Mineralogy already gets its finer pieces from Building Pieces,
without an add-on. Do not assume a Mineralogy mapping exists when the
player has disabled Mineralogy support or its slab registration. Use
`hasMaterial(materialId)` to check before contributing. The Mineralogy setting
also applies to mappings supplied by add-ons for Mineralogy source blocks.
Expand All @@ -44,7 +45,9 @@ apply at each floor's actual position. Ores remain outside the source
catalogue, but a late ore replacement beneath a generated piece is preserved.

Grass-like material mappings should provide their full dirt support state in
`supportAfterPlacement`. Register matching content orientations through the
`supportAfterPlacement`. This conversion applies only when the output covers
the whole footprint. Steps and corners retain their original support so exposed
grass remains visible. Register matching content orientations through the
Grass Slabs version 1 grass API if their lifecycle should participate
in its shared spreading rules. Content mods still own placement, drops,
rendering and migration.
Expand Down
Loading
Loading