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
21 changes: 21 additions & 0 deletions .github/workflows/deploy-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ on:
description: Four-component Modern Metals version; the target branch is derived from its fourth component.
required: true
type: string
release_commit:
description: Full commit SHA of the checked MMD target branch.
required: true
type: string
tested_jar_sha256:
description: SHA-256 of the verified Modern Metals game jar.
required: true
type: string
curseforge_release_level:
description: CurseForge release level only; this does not change the GitHub Release type.
required: true
Expand Down Expand Up @@ -135,6 +143,8 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
REQUESTED_VERSION: ${{ inputs.release_version }}
REQUESTED_COMMIT: ${{ inputs.release_commit }}
TESTED_JAR_SHA256: ${{ inputs.tested_jar_sha256 }}
run: |
set -euo pipefail

Expand Down Expand Up @@ -290,6 +300,14 @@ jobs:
fi

release_sha="$(git rev-parse HEAD)"
if [[ ! "$REQUESTED_COMMIT" =~ ^[0-9a-f]{40}$ || "$REQUESTED_COMMIT" != "$release_sha" ]]; then
echo 'The target branch no longer points at the checked release commit' >&2
exit 1
fi
if [[ ! "$TESTED_JAR_SHA256" =~ ^[0-9a-f]{64}$ ]]; then
echo 'Supply the lowercase SHA-256 of the verified game jar' >&2
exit 1
fi
release_tag="$release_version"
echo "release_sha=$release_sha" >> "$GITHUB_OUTPUT"
echo "release_version=$release_version" >> "$GITHUB_OUTPUT"
Expand Down Expand Up @@ -445,6 +463,8 @@ jobs:

- name: Stage the immutable release artifact
id: artifact
env:
TESTED_JAR_SHA256: ${{ inputs.tested_jar_sha256 }}
run: |
set -euo pipefail
bundle="$RUNNER_TEMP/release-bundle"
Expand All @@ -455,6 +475,7 @@ jobs:
cp build/release/SHA256SUMS "$bundle/"
cp CHANGELOG.txt "$bundle/"
(cd "$bundle" && sha256sum --check SHA256SUMS)
printf '%s %s\n' "$TESTED_JAR_SHA256" "$bundle/$MAIN_JAR" | sha256sum --check -
echo "name=ModernMetals-${{ needs.preflight.outputs.minecraft_version }}-${{ needs.preflight.outputs.loader_name }}-${{ needs.preflight.outputs.release_sha }}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_OUTPUT"

- name: Upload immutable release artifact
Expand Down
26 changes: 12 additions & 14 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
2.5.1.110021 for 1.10.2

- Updated the build and Eclipse setup to ForgeGradle 7, keeping Java 8 support.
- Added build checks and release workflows.
- Requires Base Metals 2.5.1.110021 and MMD OreSpawn 4.1.2.110021.
- Fixed material settings so enabled metals register their blocks, items and recipes.
- Finished boron, beryllium and thorium, including molten forms, buckets and ore generation.
- Moved ore generation to OreSpawn 4, with support for older configs and saved settings.
- Kept titanium's rutile and magnesium recipe. Titanium ore generation is optional and off by default.
- Added settings access from both the Forge mod list and OreSpawn's Mods list.
- Added High and Low Fantasy settings to ModernMetals.cfg and the config screen. Changes need a restart.
- Low Fantasy restricts unrealistic equipment, building recipes, gears, trades and Tinkers parts.
- Fixed Modern Metals processing recipes with IC2 and Mekanism.
- Fixed aluminum part casting when Tinkers has already registered the fluid.
- Added the missing upper slab models for boron, beryllium and thorium.
- Moved Java packages to zone.moddev.mc.modernmetals. Existing block and item IDs are unchanged.
This brings the 1.10.2 branch up to date. Use Java 8, Forge 12.18.3.2511 or later for 1.10.2, Base Metals 2.5.1.110021 and MMD OreSpawn 4.1.2.110021.

- Restored boron, beryllium and thorium, including their ores, molten forms and recipes.
- Kept titanium's rutile and magnesium recipe. Titanium ore generation is optional and starts off.
- Moved ore generation to OreSpawn 4. Existing OreSpawn settings can carry forward and retrogen stays off.
- Used KiriCattus's ore overlays so the stone in your resource pack shows through. Thorium keeps its original texture.
- Put Modern Metals settings in both the Forge Mods menu and OreSpawn's Mods list. The screens have German, Simplified Chinese and Russian translations, with regional English files also included.
- Added High and Low Fantasy and a switch for new villager trades. Restart after changing them. Clients need the same Fantasy Level as their server.
- Fixed IC2 and Mekanism processing and a Tinkers casting issue when the aluminum fluid was already registered.
- Checked all 20 ores with the Base Metals crusher registry and the baseSteam and baseElectric crusher lookups.
- Restored old door, fishing rod, horse armor, alloy ore and molten aluminum brass IDs for 0.11.0 worlds. Back up an older world before opening it with the new jars.
- Updated the build and Eclipse setup to ForgeGradle 7. The game still runs on Java 8.
26 changes: 22 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,41 @@ is **off by default**. If enabled, it uses the same placement settings as rutile

Open **Mods -> Modern Metals -> Config**, or choose Modern Metals from OreSpawn's
**Mods** list. Both open the same screen and save to `config/ModernMetals.cfg`.
Done saves your changes; Escape cancels them. Restart the game or server to apply
Done saves your changes. Escape cancels them. Restart the game or server to apply
them. Keep materials enabled in worlds that use their blocks and items.

**Fantasy Level** defaults to High Fantasy, which keeps the usual recipes. Low
Fantasy restricts unrealistic equipment and building recipes across the materials,
including trades and Tinkers parts. In 1.10 this is a Modern Metals setting and is
independent of Base Metals. See [the fantasy settings](docs/CONTENT_MODE.md) for
the full list of restrictions.
the full list of restrictions. A multiplayer server and its clients need the
same Fantasy Level. Use **Villager Trades** to turn off new Modern Metals offers
in either mode.

The config screen is available in English, German, Simplified Chinese and
Russian. Regional English strings are included for Australia, Canada, the UK,
New Zealand and Pirate Speak.

Ore generation is handled by OreSpawn 4. Use its editor to change ore settings.
Existing chunks are left alone and retrogen stays off. See [ore generation and
migration](docs/ORE_GENERATION.md) for defaults, ore groups and older config files.
Ores use KiriCattus's overlays over the stone texture, so stone resource packs
also change the background of the ore. Thorium keeps its original texture.

Modern Metals ores work in the Base Metals Crack Hammer and in the rock
crushers from baseSteam and baseElectric. They use the Base Metals crusher
settings, including the powder yield and any ores you disable there.

## Updating an older 1.10.2 world

Keep a backup before opening the world with the new jars. Modern Metals resolves
the old door, fishing rod, horse armor and molten aluminum brass IDs from 0.11.0.
Placed galvanized steel, nichrome and stainless steel ores still load. Those
three ores have no default OreSpawn rules. Keep the materials enabled when first
opening a world that contains them.

## Development

The build uses ForgeGradle 7 and still produces Java 8 jars. See [building and
Eclipse](docs/BUILDING.md), [integration checks and known limits](tools/validation/legacy110/README.md)
and [release preparation](docs/RELEASING.md).

The 1.11 and 1.12 branches will be updated separately.
10 changes: 10 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ def normalizeText = { details ->
eof: FixCrLfFilter.AddAsisRemove.newInstance('asis'))
}

// Preserve the tested game jar's line endings for this compatibility list.
def legacyApiList = 'META-INF/modernmetals-legacy-api.list'
def normalizeLegacyApi = { details ->
details.filter(FixCrLfFilter, eol: FixCrLfFilter.CrLf.newInstance('crlf'),
eof: FixCrLfFilter.AddAsisRemove.newInstance('asis'))
}

def developmentOutput = layout.buildDirectory.dir('forge10-development/main')
def prepareDevelopmentMod = tasks.register('prepareDevelopmentMod', Sync) {
group = 'ide'
Expand Down Expand Up @@ -150,6 +157,7 @@ tasks.named('processResources', ProcessResources) {
filesMatching('mcmod.info') { expand version: project.version, mcversion: project.minecraft_version }
rename '(.+_at.cfg)', 'META-INF/$1'
filesMatching(textPatterns, normalizeText)
filesMatching(legacyApiList, normalizeLegacyApi)
}

tasks.named('jar', Jar) {
Expand All @@ -165,10 +173,12 @@ tasks.named('jar', Jar) {
tasks.named(name, Jar) {
filteringCharset = 'UTF-8'
filesMatching(textPatterns, normalizeText)
filesMatching(legacyApiList, normalizeLegacyApi)
}
}

ext.modernMetalsBuild = [developmentOutput: developmentOutput].asImmutable()
apply from: 'gradle/ore-models.gradle'
apply from: 'gradle/release/artifacts.gradle'
apply from: 'gradle/release/publishing.gradle'
apply from: 'gradle/verification/runtime.gradle'
Expand Down
3 changes: 3 additions & 0 deletions docs/BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ metadata is not duplicated. `verifyEclipseProductionClasspath` checks isolation.

## Verification

`generateOreModels` generates the ore block models as part of the normal build.
See [ore overlays](ORE_OVERLAYS.md) for the inputs, output and client checks.

`test` covers config switches, provider conversion, titanium defaults, fantasy
policy and namespace compatibility. `verifyProjectResources` parses resources,
checks material assets, validates the provider against the pinned OreSpawn schema
Expand Down
11 changes: 9 additions & 2 deletions docs/CONTENT_MODE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,28 @@
In Minecraft 1.10.2, Modern Metals owns its fantasy setting. Open **Mods → Modern
Metals → Config → Fantasy Level** and choose **High Fantasy** or **Low Fantasy**.
The same selector is available through OreSpawn's child Mods list. Save with Done
and restart the game/server to apply the recipes. Clients and servers should use
matching settings.
and restart the game or server to apply the recipes. Forge checks for matching
settings before joining a multiplayer world and explains how to fix a mismatch.
Use the same build on both sides so the check is available.

The setting is stored in **`config/ModernMetals.cfg`**:

```text
general {
S:contentMode=low_fantasy
B:enableVillagerTrades=true
}
```

High Fantasy is the default. Missing or invalid values use High Fantasy; invalid
file values are normalized at startup. Changes remain pending until a full restart
and do not rewrite live registries or recipes.

**Villager Trades** defaults to on. Turn it off to stop new Modern Metals
blacksmith offers in either fantasy mode. The change applies after restart.
Offers already stored in a villager's inventory and offers from Base Metals
keep their existing behavior.

The 1.10 version does not read or change Base Metals' fantasy setting or recipes.
If an earlier local candidate used `BaseMetals.cfg`, move the desired value to
`ModernMetals.cfg`. Core-mod inheritance is reserved for the 1.12 modernization.
Expand Down
31 changes: 31 additions & 0 deletions docs/ORE_OVERLAYS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Ore overlays in Forge 1.10.2

Ore models use Minecraft's stone texture underneath KiriCattus's transparent
ore art. A resource pack that replaces stone also changes the stone part of
the ore. Thorium still uses its original full texture.

Forge 1.10 predates Minecraft's data generator. Run `gradlew generateOreModels`
to generate the models without starting the game. The normal build runs it
automatically, and Eclipse uses the processed resources. The inputs are the
existing ore blockstates and PNGs in
`src/main/resources/assets/modernmetals/textures/blocks/ore_overlays/`.
Generated models go to `build/generated/ore-models`; nothing is written to
`src`. Existing blockstate and item model IDs still point to the same block
model names.

The generated models use the two cubes from Base Metals' generator. The outer
cube sits 0.05 model units above the host faces so they do not fight over the
same depth. On Forge 1.10 both cubes render in the cutout layer with mipmaps,
so the transparent pixels leave the host visible. The ore blocks still inherit
their mining and drop behaviour from Base Metals.

The 20 overlay files come from [KiriCattus's art commit](https://github.com/MinecraftModDevelopmentMods/ModernMetals/commit/6c892309ab9c2cd19371a8a65ad59b250a647216).
Nineteen are used by registered ores, including the three alloy ores restored
for worlds saved by 0.11.0. The aluminum brass overlay is available as an asset.
OreSpawn still uses the same 17 rules, with titanium disabled by default.

`verifyProjectResources` checks the generated resources and texture references.
The packaged client probe checks the placed and inventory models, face offsets
and render layer. Add `--ore-host-pack` on its reload run to test a replacement
stone texture and capture the ore display. See the
[validation guide](../tools/validation/legacy110/README.md).
8 changes: 7 additions & 1 deletion docs/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ CodeQL/wrapper checks are separate. Actions use full commit hashes.

Versions use `Major.Minor.Patch.110021`. Tags validate metadata/prior CI without
publishing. The dispatcher requires `confirm_live_publication`, the upstream
repository, matching target/tag/commit and successful hosted checks. It publishes
repository, the full checked target commit, the verified game jar's SHA-256
and successful hosted checks. It publishes
the same candidate bytes to Maven, CurseForge **244357**, then GitHub. CurseForge
requires Base Metals **240967** and MMD OreSpawn **245586**, with Additional Loot
Tables **243157** optional. Credentials and an HTTPS Maven target are required.
Expand All @@ -21,3 +22,8 @@ The dispatcher must be installed on the repository's default branch before a
manual release can be started. Merging the 1.10 branch does not install it on the
1.12 default branch. Publication is a separate step and needs approval. If an
upload times out, check its status before trying again.

For the default-branch change, copy only the audited `deploy-release.yml`. It
routes the 1.10.2 suffix to the modernized branch and builds there. After a
release is publicly available, update the Forge 1.10.2 entries in `update.json`
to the exact version reported by Forge.
71 changes: 71 additions & 0 deletions gradle/ore-models.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import groovy.json.JsonOutput

// Forge 1.10 has no GatherDataEvent. Generate the equivalent model resources
// before processResources, without launching Minecraft or writing into src.
def assets = layout.projectDirectory.dir('src/main/resources/assets/modernmetals')
def overlayFiles = fileTree(assets.dir('textures/blocks/ore_overlays')) { include '*_ore.png' }
def oreStates = fileTree(assets.dir('blockstates')) { include '*_ore.json' }
def generated = layout.buildDirectory.dir('generated/ore-models')

def generateOreModels = tasks.register('generateOreModels') {
group = 'build'
description = 'Generates the Forge 1.10 ore models from KiriCattus’s overlays.'
inputs.files(overlayFiles, oreStates).withPathSensitivity(PathSensitivity.RELATIVE)
outputs.dir(generated)

doLast {
def names = overlayFiles.files.collect { it.name - '.png' }.sort()
def expected = oreStates.files.collect { it.name - '.json' }.findAll { it != 'thorium_ore' }.sort()
if (names != expected) {
throw new GradleException("Ore overlays do not match ore blockstates: missing ${expected - names}, extra ${names - expected}")
}

def dir = generated.get().dir('assets/modernmetals/models/block').asFile
dir.mkdirs()
def writeModel = { String name, Map model ->
new File(dir, "${name}.json").setText(JsonOutput.prettyPrint(JsonOutput.toJson(model)) + '\n', 'UTF-8')
}
def cube = { Number from, Number to, String texture ->
def faces = ['down', 'up', 'north', 'south', 'west', 'east'].collectEntries { face ->
[(face): [texture: texture, cullface: face, uv: [0, 0, 16, 16]]]
}
[from: [from, from, from], to: [to, to, to], faces: faces]
}
// Same two cubes and offset as Base Metals, with the legacy texture paths.
writeModel('ore_overlay', [
parent: 'minecraft:block/block',
elements: [cube(0, 16, '#base'), cube(-0.05, 16.05, '#overlay')]
])
names.each { name ->
writeModel(name, [
parent: 'modernmetals:block/ore_overlay',
textures: [particle: 'minecraft:blocks/stone', base: 'minecraft:blocks/stone',
overlay: "modernmetals:blocks/ore_overlays/${name}"]
])
}
// Clean up only obsolete ore JSON files in this task's own output directory.
dir.listFiles().findAll { it.isFile() && it.name.endsWith('_ore.json') && !(it.name - '.json' in names) }.each {
if (!it.delete()) throw new GradleException("Could not remove stale generated ore model ${it.name}")
}
}
}

tasks.named('processResources', ProcessResources) {
dependsOn generateOreModels
from generated
duplicatesStrategy = DuplicatesStrategy.FAIL
doFirst {
// Copy tasks can leave the old flat textures behind after an incremental upgrade.
overlayFiles.files.each { overlay ->
def flat = new File(destinationDir, "assets/modernmetals/textures/blocks/${overlay.name}")
if (flat.isFile() && !flat.delete()) {
throw new GradleException("Could not remove obsolete processed texture ${flat.name}")
}
}
}
}

tasks.named('sourcesJar', Jar) {
dependsOn generateOreModels
from generated
}
1 change: 1 addition & 0 deletions gradle/verification/runtime.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ tasks.named('test', Test) {
tasks.register('verifyProjectResources', Exec) {
group = 'verification'
dependsOn tasks.named('test')
dependsOn tasks.named('processResources')
doFirst {
commandLine providers.gradleProperty('pythonExecutable').getOrElse('python3'),
'tools/validation/legacy110/audit_resources.py', '--mirror',
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/zone/moddev/mc/modernmetals/ModernMetals.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.apache.logging.log4j.Logger;

import zone.moddev.mc.modernmetals.proxy.CommonProxy;
import zone.moddev.mc.modernmetals.compat.LegacyRegistryMappings;

import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
Expand All @@ -12,6 +13,7 @@
import net.minecraftforge.fml.common.event.FMLFingerprintViolationEvent;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLMissingMappingsEvent;
import net.minecraftforge.fml.common.event.FMLModIdMappingEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;

Expand Down Expand Up @@ -80,6 +82,11 @@ public static void onRemap(FMLMissingMappingsEvent event) {
proxy.onRemap(event);
}

@EventHandler
public static void onIdMapping(FMLModIdMappingEvent event) {
LegacyRegistryMappings.restoreItemAliases();
}

@EventHandler
public static void loadComplete(net.minecraftforge.fml.common.event.FMLLoadCompleteEvent event) {
zone.moddev.mc.modernmetals.content.ContentPolicy.filterRecipes();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package zone.moddev.mc.modernmetals.block;

import com.mcmoddev.lib.block.BlockMMDOre;
import com.mcmoddev.lib.material.MMDMaterial;
import net.minecraft.util.BlockRenderLayer;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

/** The shared ore block with alpha testing enabled for its model's outer faces. */
public final class OverlayOreBlock extends BlockMMDOre {
public OverlayOreBlock(MMDMaterial material) {
super(material);
}

@Override
@SideOnly(Side.CLIENT)
public BlockRenderLayer getBlockLayer() {
return BlockRenderLayer.CUTOUT_MIPPED;
}
}
Loading
Loading