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
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
/LICENSE text eol=lf
/gradlew text eol=lf
*.bat text eol=crlf
*.cfg text eol=lf
*.gradle text eol=lf
*.info text eol=lf
*.java text eol=lf
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,9 @@ jobs:
if-no-files-found: error
retention-days: 30
path: |
build/libs/RealisticDeposits-0.1.1.110021.jar
build/libs/RealisticDeposits-0.1.1.110021-sources.jar
build/libs/RealisticDeposits-0.1.1.110021-javadoc.jar
build/libs/RealisticDeposits-0.2.0.110021.jar
build/libs/RealisticDeposits-0.2.0.110021-sources.jar
build/libs/RealisticDeposits-0.2.0.110021-javadoc.jar
build/release/SHA256SUMS
CHANGELOG.md

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/deploy-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ on:
curseforge_release_level:
description: CurseForge release level only; this does not change the GitHub Release type.
required: true
default: alpha
default: beta
type: choice
options:
- release
Expand Down Expand Up @@ -416,7 +416,7 @@ jobs:
echo "- Target branch: \`$RELEASE_BRANCH\`"
echo "- Commit: \`$RELEASE_SHA\`"
echo "- CurseForge release level: \`$RELEASE_LEVEL\`"
echo "- GitHub Release type: ordinary release"
echo "- GitHub Release type: prerelease"
echo
echo "### Public artifact checksums"
echo '```text'
Expand Down
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
# Changelog

## 0.2.0.110021

Beta for Minecraft 1.10.2.

- Add large coalfields with two to four thin beds, shared folds and faults,
gradual thinning and local rock partings. Keep 15% background coal for early
play and retain vanilla coal drops and Fortune behaviour.
- Fit coal beds to suitable existing sedimentary rocks when Mineralogy geology
is active. Use plain stone otherwise, without adding rocks or enabling
terrain replacement. Keep granite, diorite, andesite and unsuitable hosts out.
- Keep the coal catalogue separate from iron. Preserve existing settings,
world profiles, legacy coal layers and previously generated terrain.
- Require OreSpawn 4.1.4.110021 so coal replaces only the intended rock variants.
Download and check the release automatically.

- Add optional abandoned workings to deposits: a surface shaft, ladder access,
short seam-following galleries, timber supports, broken rails, cobwebs and
small rubble piles. Mines are off by default, with a separate chance for each
deposit definition.
- Keep mine layouts stable through reloads and later exploration. Protect old
chunks, and finish only the unbuilt sections of an already accepted plan.
- Skip unsafe sites and leave obstructions sealed rather than cutting into
liquids or another structure. Mines do not reroll deposit selection or
produce item drops while carving.
- Add a separate Eclipse mine-testing profile without changing ordinary saves
or configuration.

## 0.1.1.110021

- Let pack authors define deposits in JSON, starting with a supplied iron
Expand Down
46 changes: 35 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ projects.
The project starts with Minecraft 1.10.2 and is intended to follow the
maintained OreSpawn branches across Forge and NeoForge.

This is an alpha. The supplied catalog currently adds iron only. Back up your
world before updating, and expect the defaults to change as testing continues.
This beta adds coalfields and optional abandoned workings
alongside the existing iron districts. Back up your world before updating.

Coalfields use the exact-host API in the published OreSpawn 4.1.4.110021 release.

## Current features

Expand All @@ -30,6 +32,9 @@ world before updating, and expect the defaults to change as testing continues.
around the fault gaps instead of making the displaced ore impossible to
rediscover. Each chunk writes only its own deterministic part of a deposit.
- Massive-and-rare, geome-aware, and host-rock-aware generation modes.
- Coalfields with several thin beds, folds, fault offsets and local rock
partings. Existing Mineralogy sedimentary rocks are used when available;
Mineralogy is not required. See [coalfields](docs/COALFIELDS.md).
- Additive, hybrid, and replacement policies for controlling interaction with
ordinary ore generation.
- Configurable support for vanilla and modded resources.
Expand All @@ -38,18 +43,20 @@ world before updating, and expect the defaults to change as testing continues.
- Live reload for geometry and alignment tuning, with structural changes
clearly deferred until restart.
- An entry in both Forge's Mods configuration and OreSpawn's World Settings.
- Optional abandoned workings, with surface access and short seam-following
galleries. They are off by default; see the [mine settings](docs/ABANDONED_MINES.md).

Compatibility catalogs for Mineralogy, Base Metals, Modern Metals, Base
Minerals, and Base Gems will be added as those product lines become available
on each target.
Coalfields can already use Mineralogy's existing shale, siltstone and
conglomerate. Wider catalogues for Mineralogy, Base Metals, Modern Metals,
Base Minerals and Base Gems remain future work.

## Requirements

The current branch requires:

- Minecraft 1.10.2;
- Forge 12.18.3.2511 or a compatible newer Forge 12 build;
- [MMD OreSpawn 4.1.3.110021](https://www.curseforge.com/minecraft/mc-mods/mmd-orespawn/files/9335434)
- [MMD OreSpawn 4.1.4.110021](https://www.curseforge.com/minecraft/mc-mods/mmd-orespawn/files/9356289)
or a newer compatible 1.10.2 release, but earlier than OreSpawn 5;
- Java 8 to run Minecraft.

Expand All @@ -63,6 +70,7 @@ The first launch creates:

```text
config/realisticdeposits/deposits/vanilla.json
config/realisticdeposits/deposits/coal.json
```

The supplied definition describes one rare iron district using a 640–960 block
Expand All @@ -74,6 +82,13 @@ The shipped iron definition uses `hybrid` interaction with 15% background iron
so early play remains viable while a discovered district can support a
long-lived mine and rail network.

The separate coal catalogue adds two to four beds across a large coalfield,
keeping 15% ordinary background coal. It favours sedimentary and wetland basins
while allowing sedimentary cover in some other geological regions. Coalfields
use plain stone without physical strata, or suitable existing sedimentary
rocks when those strata are active. Old catalogues are never overwritten, and
old worlds do not receive new coal rules automatically.

Deposits only affect newly generated chunks. Changing these settings does not
retrogen, replace, or rewrite an existing chunk.

Expand Down Expand Up @@ -120,7 +135,8 @@ formations:
`reload` requires operator permission. It immediately applies `enabled`,
selection, shape, height, geome, family, and alignment changes. Resource,
dimension, host, biome-filter, interaction-policy, scale, added, and removed
definition changes are structural and take effect after restart. New provider
definition changes are structural and take effect after restart. Abandoned-mine
settings are also captured with the world's deposit definition. New provider
entries are deliberately not injected into a world profile that already
exists.

Expand All @@ -132,10 +148,14 @@ World Settings screen.
The Gradle build runs on Java 17 and compiles the mod for Java 8 using the
configured toolchain. ForgeGradle's Minecraft preparation utility uses Java 25.

OreSpawn 4.1.3.110021 is downloaded from Curse Maven, checked against the
official release checksum and mapped for development automatically. No sibling
checkout, local OreSpawn build or `local.properties` file is needed.
The exact dependency is `curse.maven:mmd-orespawn-245586:9335434`.
OreSpawn 4.1.4.110021 is downloaded from Curse Maven, checked against its
official checksum and mapped for development automatically. The exact dependency
is `curse.maven:mmd-orespawn-245586:9356289`. No sibling checkout, local jar or
`local.properties` file is needed.

An optional local-candidate override is still available for development, but it
must name an isolated repository and a complete checksum. Publication is blocked
whenever that override is selected. Normal builds use the public release.

On Windows, run:

Expand All @@ -152,6 +172,10 @@ and configuration in `run-major-iron`, apart from the ordinary client launch.

The [generation qualification guide](tools/qualification/README.md) describes
the optional packaged-server checks for policies, imports and saved worlds.
The [mine-testing walkthrough](tools/qualification/MINES_TESTING.md) uses a
separate Eclipse profile and disposable saves for the new workings.
For coalfields, use `prepareCoalMeasuresManual` and the
[coal-testing walkthrough](tools/qualification/COAL_TESTING.md).

CI also checks reproducible jars, dependency hashes and ordinary Eclipse
launches. The [release guide](docs/RELEASING.md) explains the manual release
Expand Down
80 changes: 68 additions & 12 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@ if (versionParts[3] != expectedTarget) {

def oreSpawnCoordinate = "curse.maven:mmd-orespawn-${project.orespawn_curse_project_id}:" \
+ project.orespawn_curse_file_id
def localCandidate = new Properties()
if (file('local.properties').isFile()) {
file('local.properties').withInputStream { localCandidate.load(it) }
}
def candidateProperty = { String name -> providers.gradleProperty(name)
.getOrElse(localCandidate.getProperty(name, '')) }
def candidateRepository = candidateProperty('orespawnCandidateRepository')
def candidateHash = candidateProperty('orespawnCandidateSha256').toUpperCase(Locale.ROOT)
ext.oreSpawnCandidateMode = !candidateRepository.isEmpty()
if (oreSpawnCandidateMode) {
if (!(candidateHash ==~ /[0-9A-F]{64}/)) {
throw new GradleException('The local OreSpawn candidate needs its complete SHA-256')
}
oreSpawnCoordinate = "zone.moddev.mc.orespawn.candidate:OreSpawn:${project.orespawn_version}"
}
def mappedOreSpawn = renamer.dependency(oreSpawnCoordinate)

configurations {
Expand Down Expand Up @@ -136,6 +151,12 @@ tasks.configureEach {
}

repositories {
if (oreSpawnCandidateMode) {
exclusiveContent {
forRepository { maven { name = 'LocalCoalCandidate'; url = uri(candidateRepository) } }
filter { includeGroup 'zone.moddev.mc.orespawn.candidate' }
}
}
minecraft.mavenizer(it)
maven fg.forgeMaven
maven fg.minecraftLibsMaven
Expand Down Expand Up @@ -229,8 +250,10 @@ tasks.register('isolateEclipseProductionRuns') {
dependsOn tasks.named('configureEclipseBuildship')
dependsOn prepareEclipseResources
doLast {
[['runClient.launch', 'runMajorIronClient.launch'],
['runServer.launch', 'runMajorIronServer.launch']].each { pair ->
[['runClient.launch', 'runMajorIronClient.launch', 'run-major-iron'],
['runServer.launch', 'runMajorIronServer.launch', 'run-major-iron'],
['runClient.launch', 'runAbandonedMinesClient.launch', 'run-abandoned-mines'],
['runServer.launch', 'runAbandonedMinesServer.launch', 'run-abandoned-mines']].each { pair ->
File source = file(pair[0])
File target = file(pair[1])
if (!source.isFile()) {
Expand All @@ -239,11 +262,12 @@ tasks.register('isolateEclipseProductionRuns') {
String contents = source.getText('UTF-8')
contents = contents.replaceAll(
/(<stringAttribute key="org\.eclipse\.jdt\.launching\.WORKING_DIRECTORY" value=")[^"]*("\/>)/,
'$1' + file('run-major-iron').absolutePath.replace('\\', '\\\\') + '$2')
'$1' + file(pair[2]).absolutePath.replace('\\', '\\\\') + '$2')
target.setText(contents.replace('\r\n', '\n'), 'UTF-8')
}
['runClient.launch', 'runServer.launch',
'runMajorIronClient.launch', 'runMajorIronServer.launch',
'runAbandonedMinesClient.launch', 'runAbandonedMinesServer.launch',
'runTestClient.launch', 'runTestServer.launch'].each { name ->
File launch = file(name)
if (!launch.isFile()) {
Expand Down Expand Up @@ -279,7 +303,8 @@ tasks.register('isolateEclipseProductionRuns') {
programArguments[0][1] + arguments + programArguments[0][3])

if ((name == 'runClient.launch' || name == 'runServer.launch'
|| name == 'runMajorIronClient.launch' || name == 'runMajorIronServer.launch')
|| name == 'runMajorIronClient.launch' || name == 'runMajorIronServer.launch'
|| name == 'runAbandonedMinesClient.launch' || name == 'runAbandonedMinesServer.launch')
&& !contents.contains('org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE')) {
contents = contents.replace('</launchConfiguration>',
' <booleanAttribute key="org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE" value="true"/>\n'
Expand All @@ -306,7 +331,8 @@ tasks.register('verifyEclipseProductionClasspath') {
throw new GradleException('Eclipse metadata is not version-expanded')
}
['runClient.launch', 'runServer.launch',
'runMajorIronClient.launch', 'runMajorIronServer.launch'].each { name ->
'runMajorIronClient.launch', 'runMajorIronServer.launch',
'runAbandonedMinesClient.launch', 'runAbandonedMinesServer.launch'].each { name ->
String contents = file(name).getText('UTF-8').replace('\\', '/')
['src/test', 'bin/test', 'build/classes/java/test', 'junit-',
'opentest4j-', 'junit-platform-'].each { forbidden ->
Expand All @@ -318,17 +344,22 @@ tasks.register('verifyEclipseProductionClasspath') {
|| !contents.contains('PROJECT_ATTR" value="RealisticDeposits"')) {
throw new GradleException("${name} is not a production-only RealisticDeposits launch")
}
if ((name == 'runServer.launch' || name == 'runMajorIronServer.launch')
if ((name == 'runServer.launch' || name == 'runMajorIronServer.launch'
|| name == 'runAbandonedMinesServer.launch')
&& (!contents.contains(' -- nogui"') || contents.contains('--nogui'))) {
throw new GradleException('Forge 1.10 server launch must use bare nogui')
}
if (name.startsWith('runMajorIron')
&& !contents.contains('run-major-iron')) {
throw new GradleException("${name} does not use the isolated major-iron directory")
}
if (name.startsWith('runAbandonedMines') && !contents.contains('run-abandoned-mines')) {
throw new GradleException("${name} does not use the isolated abandoned-mine directory")
}
}
['runClient.launch', 'runServer.launch',
'runMajorIronClient.launch', 'runMajorIronServer.launch',
'runAbandonedMinesClient.launch', 'runAbandonedMinesServer.launch',
'runTestClient.launch', 'runTestServer.launch'].each { name ->
String contents = file(name).getText('UTF-8')
['cache', 'metadata', 'to-srg', 'to-obf'].each { flag ->
Expand All @@ -340,6 +371,24 @@ tasks.register('verifyEclipseProductionClasspath') {
}
}

tasks.register('prepareAbandonedMinesManual') {
group = 'verification'
description = 'Prepares a separate mine-testing configuration and Eclipse launches.'
dependsOn tasks.named('verifyEclipseProductionClasspath')
doLast {
File catalog = file('run-abandoned-mines/config/realisticdeposits/deposits/vanilla.json')
if (!catalog.exists()) {
def settings = new groovy.json.JsonSlurper().parse(
file('src/main/resources/assets/realisticdeposits/defaults/vanilla.json'), 'UTF-8')
settings.deposits.each { it.abandoned_mine = [enabled: true, chance: 1.0] }
catalog.parentFile.mkdirs()
catalog.setText(groovy.json.JsonOutput.prettyPrint(groovy.json.JsonOutput.toJson(settings)) + '\n', 'UTF-8')
}
logger.lifecycle('Use runAbandonedMinesClient.launch. Existing manual settings and saves were not changed.')
logger.lifecycle('The walkthrough is tools/qualification/MINES_TESTING.md.')
}
}

tasks.named('jar', Jar) {
archiveClassifier = 'deobf'
destinationDirectory = layout.buildDirectory.dir('libs-dev')
Expand Down Expand Up @@ -401,11 +450,11 @@ tasks.register('verifyProjectIdentity') {
}
if (project.minecraft_version != '1.10.2'
|| project.forge_version != '12.18.3.2511'
|| project.orespawn_version != '4.1.3.110021'
|| project.orespawn_version_range != '[4.1.3.110021,5.0.0)'
|| oreSpawnCoordinate != 'curse.maven:mmd-orespawn-245586:9335434'
|| project.orespawn_version != '4.1.4.110021'
|| project.orespawn_version_range != '[4.1.4.110021,5.0.0)'
|| (!oreSpawnCandidateMode && oreSpawnCoordinate != 'curse.maven:mmd-orespawn-245586:9356289')
|| project.orespawn_sha256
!= 'FA1F4CAE66374E32162EC9543FF2BFBA236934C9E44D3F6AD882BC00761C15EF') {
!= 'DB254E9E865685A74262DE9D469A006AB3C8053573CC6136FD4A8591AD806CA3') {
throw new GradleException('Unexpected target or OreSpawn dependency identity')
}
if (project.mod_version.toString().contains('-')) {
Expand Down Expand Up @@ -448,9 +497,10 @@ tasks.register('verifyOreSpawnDependency') {
File oreSpawnFile = configurations.oreSpawnRelease.singleFile
String actualHash = java.security.MessageDigest.getInstance('SHA-256')
.digest(oreSpawnFile.bytes).encodeHex().toString().toUpperCase()
if (actualHash != project.orespawn_sha256) {
String expectedHash = oreSpawnCandidateMode ? candidateHash : project.orespawn_sha256
if (actualHash != expectedHash) {
throw new GradleException("OreSpawn SHA-256 is ${actualHash}, expected "
+ project.orespawn_sha256)
+ expectedHash)
}
java.util.zip.ZipFile archive = new java.util.zip.ZipFile(oreSpawnFile)
try {
Expand All @@ -459,6 +509,11 @@ tasks.register('verifyOreSpawnDependency') {
if (apiEntry == null || providerEntry == null) {
throw new GradleException('OreSpawn is missing the 4.1 extension API')
}
def dimensionBuilder = archive.getEntry('zone/moddev/mc/orespawn/api/WorldgenProvider$OreDimensionDefinition$Builder.class')
if (dimensionBuilder == null || !new String(archive.getInputStream(dimensionBuilder).bytes,
java.nio.charset.StandardCharsets.ISO_8859_1).contains('hostState')) {
throw new GradleException('Coalfields need the exact-host API from OreSpawn 4.1.4.110021 or later.')
}
def metadata = new groovy.json.JsonSlurper().parse(
archive.getInputStream(archive.getEntry('mcmod.info')))
def manifest = new java.util.jar.Manifest(
Expand Down Expand Up @@ -591,3 +646,4 @@ tasks.named('check') {
}

apply from: 'gradle/release.gradle'
apply from: 'gradle/coal-manual.gradle'
Loading
Loading