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
9 changes: 6 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ jobs:
gradle_args=(
clean check build javadoc verifyReleaseDependencies verifyReleaseArtifacts
writeReleaseChecksums prepareEclipse packagedForgeRuntimeTest
packagedForgeLegacyMigrationTest
-PlegacyDependencyVerificationRepository="${{ steps.dependencies.outputs.repository }}"
-PpackagedForgeRuntimeRoot="${{ steps.forge.outputs.runtime }}"
--no-daemon --stacktrace --max-workers=2
Expand Down Expand Up @@ -177,9 +178,9 @@ jobs:
if-no-files-found: error
retention-days: 30
path: |
build/libs/BaseMetals-2.6.0.112021.jar
build/libs/BaseMetals-2.6.0.112021-sources.jar
build/libs/BaseMetals-2.6.0.112021-javadoc.jar
build/libs/BaseMetals-2.6.1.112021.jar
build/libs/BaseMetals-2.6.1.112021-sources.jar
build/libs/BaseMetals-2.6.1.112021-javadoc.jar
build/release/SHA256SUMS
CHANGELOG.txt

Expand All @@ -196,4 +197,6 @@ jobs:
build/packaged-forge-*-run/logs/**
build/packaged-forge-*-run/*-console.txt
build/packaged-forge-*-run/crash-reports/**
build/packaged-forge-legacy-run/*-save.properties
build/packaged-forge-legacy-run/legacy-*.properties
build/problems/**
12 changes: 12 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
Base Metals 2.6.1.112021 — Minecraft 1.12.2

- Fixed recovery of mercury blocks, carbon powder, iron nuggets and metal door
items when loading older Base Metals worlds. Counts, damage, enchantments,
names and other item data are preserved.
- Fixed old items disappearing from chunks first visited after saving and
restarting an upgraded world. Automated checks now cover first load,
reload and these later visits.
- Keep the matching materials enabled and back up the complete world before
upgrading. Items already lost in an earlier save need a pre-loss backup;
containers and entities from other mods still need compatible versions.

Base Metals 2.6.0.112021 — Minecraft 1.12.2

Before upgrading
Expand Down
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ Base Metals adds metals, alloys, equipment, building blocks, and the crackhammer
Crush ores into powder, smelt the powder into ingots, or combine it into alloy
blends. The metals also work with supported processing and tool-building mods.

This branch builds **2.6.0.112021** for Minecraft 1.12.2 and Forge. It keeps the
existing block and item names for saved worlds, fixes long-standing gameplay
issues, and adds an optional Low Fantasy content mode. See the
This branch builds **2.6.1.112021** for Minecraft 1.12.2 and Forge. This update
fixes missing blocks and items when upgrading older Base Metals worlds. It
also keeps the gameplay fixes and optional Low Fantasy mode from 2.6.0. See the
[changelog](CHANGELOG.txt) for the release changes.

## Installation
Expand All @@ -31,6 +31,20 @@ Put the jars in the instance's `mods` folder. Minecraft 1.12.2 runs on Java 8.
Back up your worlds and configuration before upgrading. MMD OreSpawn is the
world-generation library, not the unrelated creature mod with a similar name.

## Older worlds

Older Base Metals mercury blocks, carbon powder, iron nuggets and metal door
items load under their current names. This also covers chunks first visited
after the upgraded world has already been saved and restarted. Stack counts,
damage, enchantments, names and other item data are retained.

Keep the corresponding materials enabled during the upgrade. The fix cannot
restore items already lost in an earlier save; use a backup from before the
loss instead.

Test a complete copy of the world first. Containers and entities supplied by
other mods still need their own compatible versions and upgrade support.

## Metals and alloys

The natural materials are Antimony, Bismuth, Copper, Lead, Mercury, Nickel,
Expand Down Expand Up @@ -129,7 +143,7 @@ The [build-script guide](gradle/README.md) explains the supporting scripts.
The [release guide](docs/releasing.md) covers publication from the MMD Actions tab.

Release artifacts use the Maven coordinates
`zone.moddev.mc.basemetals:BaseMetals:2.6.0.112021`. Java packages remain under
`zone.moddev.mc.basemetals:BaseMetals:2.6.1.112021`. Java packages remain under
`com.mcmoddev.basemetals`; this release does not move saved registry names.

Report bugs through the [issue tracker](https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues).
Expand Down
2 changes: 1 addition & 1 deletion docs/world-generation.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Base Metals world generation

Base Metals 2.6.0 requires OreSpawn 4.1.0.112021 or newer in the 4.x line.
Base Metals 2.6 requires OreSpawn 4.1.0.112021 or newer in the 4.x line.
OreSpawn is the only Base Metals ore generator. Base Metals does not register a
fallback generator.

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ org.gradle.parallel=false
net.minecraftforge.gradle.merge-source-sets=false

mod_group=zone.moddev.mc.basemetals
mod_version=2.6.0.112021
mod_version=2.6.1.112021

# Generic release-dispatcher metadata.
minecraft_version=1.12.2
Expand Down
13 changes: 13 additions & 0 deletions gradle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ of that main path:
- `verification/packaged-forge-dependencies.gradle` checks required OreSpawn
behavior and preservation of an existing override.
- `verification/packaged-forge-migration.gradle` covers OreSpawn 3 migration.
- `verification/packaged-forge-legacy-saves.gradle` checks old Base Metals IDs
on first load, reload, and a later visit to a previously unopened chunk.
- `verification/packaged-forge-cofh.gradle` covers the optional CoFH World
coexistence profile.
- `verification/packaged-forge-tinkers.gradle` covers Tinkers, TAIGA,
Expand All @@ -38,3 +40,14 @@ variables from another script's scope.

When adding a task, put it beside the workflow it supports. Keep task names
stable because CI and the release dispatcher call them directly.

CI runs `packagedForgeLegacyMigrationTest` against the packaged release jar.
It creates a small disposable Anvil save with the twenty historical item
names and the old Mercury block name. The test checks item counts, damage,
names, enchantments and custom data after each restart. A distant region must
remain byte-for-byte unchanged until the test visits it; its items must then
convert and survive another restart. No private world backup is needed.

For a local run, supply `-PpackagedForgeRuntimeRoot=<Forge installation>` as
with the other packaged-server tests. The fixture, logs and results stay in
`build/packaged-forge-legacy-run`; they are not release artifacts.
2 changes: 2 additions & 0 deletions gradle/release/artifacts.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ tasks.register('verifyReleaseArtifacts') {
'com/mcmoddev/basemetals/recipe/PolicyCrusherRecipe.class',
'com/mcmoddev/basemetals/recipe/PolicyRecipe.class',
'com/mcmoddev/basemetals/worldgen/BaseMetalsWorldgenProvider.class',
'com/mcmoddev/basemetals/LegacyMappings.class',
'com/mcmoddev/basemetals/LegacyStackFix.class',
'assets/mmdlib/lang/en_us.lang',
'assets/mmdlib/lang/es_es.lang'
]
Expand Down
80 changes: 80 additions & 0 deletions gradle/verification/packaged-forge-legacy-saves.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
def runtime = project.ext.baseMetalsPackagedForge
File runDirectory = layout.buildDirectory.dir('packaged-forge-legacy-run').get().asFile
File marker = new File(runDirectory, 'legacy-probe.properties')

def prepare = tasks.register('preparePackagedLegacySave') {
dependsOn runtime.releaseJar, runtime.packagedLegacyRuntimeProbeJar,
tasks.named('verifyReleaseDependencies')
doLast {
// Never point the cleanup or fixture writer at a player's save.
if (!runDirectory.canonicalFile.toPath().startsWith(layout.buildDirectory.get().asFile.canonicalFile.toPath())) {
throw new GradleException('The legacy fixture must stay inside build/')
}
runtime.stagePackagedForgeBase(runDirectory)
copy {
from layout.buildDirectory.file("libs/BaseMetals-${project.version}.jar")
from layout.buildDirectory.file('runtime-probes/basemetals-legacy-runtime-probe.jar')
from runtime.originalArtifact(configurations.legacyDependencyArtifacts,
runtime.dependencySpecs.mmdlib.coordinate)
from runtime.originalArtifact(configurations.legacyDependencyArtifacts,
runtime.dependencySpecs.orespawn4.coordinate)
into new File(runDirectory, 'mods')
}
File properties = new File(runDirectory, 'server.properties')
properties.setText(properties.getText('UTF-8').replace('level-type=default', 'level-type=flat'), 'UTF-8')
}
}

def previous = prepare
['Seed', 'First', 'Reload', 'Delayed', 'Stable'].each { phase ->
def dependency = previous
def boot = tasks.register("packagedLegacySave${phase}", Exec) {
dependsOn dependency
workingDir runDirectory
timeout = java.time.Duration.ofMinutes(3)
ignoreExitValue = true
doFirst {
marker.delete()
// File-backed output survives assertion failures and process timeouts.
File console = new File(runDirectory, "${phase.toLowerCase()}-console.txt")
standardOutput = new FileOutputStream(console)
errorOutput = standardOutput
commandLine runtime.java8Launcher.get().executablePath.asFile,
'-Xmx2G', '-Dforge.logging.console.level=info',
'-Dbasemetals.legacyProbe.ciFixture=true',
"-Dbasemetals.legacyProbe.phase=${phase.toLowerCase()}",
"-Dbasemetals.legacyProbe.marker=${marker.absolutePath}",
'-jar', new File(runDirectory,
"forge-${project.minecraft_version}-${project.forge_version}-universal.jar"), 'nogui'
}
doLast {
standardOutput.close()
if (executionResult.get().exitValue != 0 || !marker.isFile()) {
throw new GradleException("Legacy save ${phase} failed; see ${runDirectory}")
}
Properties result = new Properties()
marker.withInputStream { result.load(it) }
if (result.getProperty('phase') != phase.toLowerCase() || result.getProperty('passed') != 'true') {
throw new GradleException("Invalid legacy save result: ${result}")
}
def failures = runtime.runtimeLogFailures(runDirectory)
if (!failures.isEmpty() || !fileTree(runDirectory) { include 'crash-reports/*.txt' }.isEmpty()) {
throw new GradleException("Legacy save ${phase} logged runtime failures: ${failures.take(10)}")
}
}
}

previous = tasks.register("verifyLegacySave${phase}", JavaExec) {
dependsOn boot
javaLauncher = runtime.java8Launcher
classpath = sourceSets.test.runtimeClasspath
mainClass = 'com.mcmoddev.basemetals.test.LegacySaveFixture'
args phase == 'Seed' ? 'prepare' : phase.toLowerCase(), runDirectory.absolutePath
}
}

tasks.register('packagedForgeLegacyMigrationTest') {
group = 'verification'
description = 'Checks old registry names on first load, reload, and a later visit to an unopened chunk.'
dependsOn previous
}
27 changes: 27 additions & 0 deletions gradle/verification/packaged-forge.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,31 @@ tasks.register('packagedRuntimeProbes') {
dependsOn packagedRuntimeProbeJar
}

tasks.register('legacyRuntimeProbeJar', Jar) {
group = 'verification'
description = 'Builds the test-only legacy-save registry and inventory probe.'
dependsOn tasks.named('testClasses')
archiveBaseName = 'basemetals-legacy-runtime-probe'
archiveVersion = ''
archiveClassifier = 'deobf'
destinationDirectory = layout.buildDirectory.dir('runtime-probes-dev')
from(sourceSets.test.output) {
include 'com/mcmoddev/basemetals/test/BaseMetalsLegacyRuntimeProbe*.class'
include 'com/mcmoddev/basemetals/test/LegacySaveFixture.class'
}
}

def packagedLegacyRuntimeProbeJar = renamer.classes(tasks.named('legacyRuntimeProbeJar', Jar)) {
map.from minecraft.dependency.toSrgFile
archiveClassifier = null
output = layout.buildDirectory.file('runtime-probes/basemetals-legacy-runtime-probe.jar')
}

tasks.register('packagedLegacyRuntimeProbe') {
group = 'verification'
dependsOn packagedLegacyRuntimeProbeJar
}

tasks.register('tinkersRuntimeProbeJar', Jar) {
group = 'verification'
description = 'Builds the mapped test-only Tinkers/TAIGA compatibility probe.'
Expand Down Expand Up @@ -372,6 +397,7 @@ ext.baseMetalsPackagedForge = [
releaseJar : releaseJar,
java8Launcher : java8Launcher,
packagedRuntimeProbeJar : packagedRuntimeProbeJar,
packagedLegacyRuntimeProbeJar : packagedLegacyRuntimeProbeJar,
packagedTinkersRuntimeProbeJar : packagedTinkersRuntimeProbeJar,
packagedClientConfigRuntimeProbeJar : packagedClientConfigRuntimeProbeJar,
packagedForgeRuntimeRoot : packagedForgeRuntimeRoot,
Expand All @@ -384,6 +410,7 @@ ext.baseMetalsPackagedForge = [

apply from: 'gradle/verification/packaged-forge-dependencies.gradle'
apply from: 'gradle/verification/packaged-forge-migration.gradle'
apply from: 'gradle/verification/packaged-forge-legacy-saves.gradle'
apply from: 'gradle/verification/packaged-forge-cofh.gradle'
apply from: 'gradle/verification/packaged-forge-tinkers.gradle'
apply from: 'gradle/verification/packaged-advancements.gradle'
4 changes: 2 additions & 2 deletions gradle/verification/support.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ tasks.register('verifyReleaseConfiguration') {
description = 'Validates the complete Base Metals 1.12 release identity and dependency contract.'
dependsOn tasks.named('verifyReleaseToolchains')
doLast {
if (project.mod_version != '2.6.0.112021'
if (project.mod_version != '2.6.1.112021'
|| project.minecraft_version != '1.12.2'
|| project.forge_version != '14.23.5.2859'
|| project.mappings_channel != 'stable'
Expand Down Expand Up @@ -130,7 +130,7 @@ tasks.register('verifyReleaseConfiguration') {
throw new GradleException('Unexpected published OreSpawn 4.1 CurseForge artifact identity')
}
String source = file('src/main/java/com/mcmoddev/basemetals/BaseMetals.java').getText('UTF-8')
if (!source.contains('VERSION = "2.6.0.112021"')
if (!source.contains('VERSION = "2.6.1.112021"')
|| !source.contains('certificateFingerprint = ""')
|| !source.contains('required-after:orespawn@[4.1.0.112021,5.0.0)')) {
throw new GradleException('Base Metals source version or unsigned fingerprint contract drifted')
Expand Down
1 change: 1 addition & 0 deletions gradle/verification/workflows.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ tasks.register('verifyWorkflowContracts') {
'master-1.12', 'feature/**', 'Cold Forge bootstrap',
'Build, test, and audit', 'stage-legacy-dependencies.sh',
'packagedForgeRuntimeTest', 'prepareEclipse',
'packagedForgeLegacyMigrationTest',
'Verify reproducible release archives'
],
'codeql-analysis.yml': [
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/mcmoddev/basemetals/BaseMetals.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public final class BaseMetals {
protected static final String NAME = "Base Metals";

/** Release version in the shared MMD major.minor.patch.target format. */
protected static final String VERSION = "2.6.0.112021";
protected static final String VERSION = "2.6.1.112021";

protected static final String UPDATEJSON = SharedStrings.UPDATE_JSON_URL
+ "BaseMetals/master/update.json";
Expand Down Expand Up @@ -104,13 +104,13 @@ public static void postInit(final FMLPostInitializationEvent event) {

/** Restores historical block IDs when Forge loads an older save. */
@SubscribeEvent
public void onRemapBlock(final RegistryEvent.MissingMappings<Block> event) {
public static void onRemapBlock(final RegistryEvent.MissingMappings<Block> event) {
proxy.onRemapBlock(event);
}

/** Restores historical item IDs when Forge loads an older save. */
@SubscribeEvent
public void onRemapItem(final RegistryEvent.MissingMappings<Item> event) {
public static void onRemapItem(final RegistryEvent.MissingMappings<Item> event) {
proxy.onRemapItem(event);
}
}
49 changes: 49 additions & 0 deletions src/main/java/com/mcmoddev/basemetals/LegacyMappings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.mcmoddev.basemetals;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

import net.minecraft.util.datafix.FixTypes;
import net.minecraftforge.common.util.ModFixs;
import net.minecraftforge.fml.common.FMLCommonHandler;

/** Historical registry names whose equivalent content is still available. */
public final class LegacyMappings {

private static final Map<String, String> ITEMS = itemAliases();

private LegacyMappings() {
}

/** Registers raw-stack recovery before chunks, players and entities are deserialized. */
public static void registerDataFixer() {
ModFixs fixes = FMLCommonHandler.instance().getDataFixer().init(BaseMetals.MODID, 1);
LegacyStackFix fix = new LegacyStackFix();
for (FixTypes type : new FixTypes[] { FixTypes.CHUNK, FixTypes.PLAYER, FixTypes.ENTITY,
FixTypes.BLOCK_ENTITY, FixTypes.ITEM_INSTANCE }) fixes.registerFix(type, fix);
}

/** Returns the current item name, or null for an unrelated registry entry. */
public static String itemTarget(final String name) {
return ITEMS.get(name);
}

/** Returns the current fluid-block name, or null for an unrelated entry. */
public static String blockTarget(final String name) {
return "basemetals:liquid_mercury".equals(name) ? "basemetals:mercury" : null;
}

private static Map<String, String> itemAliases() {
final Map<String, String> aliases = new LinkedHashMap<>();
aliases.put("basemetals:liquid_mercury", "basemetals:mercury");
aliases.put("basemetals:carbon_powder", "basemetals:coal_powder");
aliases.put("basemetals:iron_nugget", "minecraft:iron_nugget");
for (String material : new String[] { "adamantine", "aquarium", "brass", "bronze",
"coldiron", "copper", "cupronickel", "electrum", "invar", "lead", "mithril",
"nickel", "platinum", "silver", "starsteel", "steel", "tin" }) {
aliases.put("basemetals:" + material + "_door_item", "basemetals:" + material + "_door");
}
return Collections.unmodifiableMap(aliases);
}
}
Loading
Loading