From e3accaf83fd144c47d3c8a6f2ddcd9f60e0170e7 Mon Sep 17 00:00:00 2001 From: The_miro Date: Wed, 12 Aug 2026 19:19:36 +0200 Subject: [PATCH] Add Immersive Engineering materials, fix gem sockets, pick one provider per metal Gem sockets never accepted the two Iron's Spells essences: Arsenal gates its melee gem modules on the `gem_melee` material group and Armory gates its armour ones on `gem_armor`, neither of which is the `gem` group they carried. Every gem-like material now carries both, so it fits any gem slot. Immersive Engineering adds aluminium, nickel, constantan, electrum and graphite. Its steel, lead, uranium and silver overlap mods already covered, so rather than one material accepting either mod's ingot, each metal simply names one provider - Mekanism for steel/lead/uranium, Ice and Fire for silver. That keeps one entry per metal in the crafting screen. Titanium moves to the same rule with Cosmonautics as its provider, which drops the c: tag files and the any-of pack machinery along with it. That also removes a latent crash: a tag-fed material still needed an item for its icon, and MIAPI parses icon items through the registry and throws when one is missing. The generator now clears its output directory first, so a material that moves between packs cannot leave a stale copy claiming the same id. Co-Authored-By: Claude Opus 5 --- README.md | 26 +++-- .../eu/abdelbaki/cmmodular/CMModular.java | 37 +++--- .../resources/META-INF/neoforge.mods.toml | 7 ++ .../data/c/tags/item/ingots/titanium.json | 9 -- .../data/c/tags/item/nuggets/titanium.json | 9 -- .../data/c/tags/item/plates/titanium.json | 9 -- .../resources/packs/aerospace/pack.mcmeta | 6 - .../miapi/materials/crystal/sulfur.json | 4 +- .../miapi/materials/metal/titanium.json | 10 +- .../miapi/materials/crystal/dread_shard.json | 4 +- .../miapi/materials/crystal/pixie_dust.json | 4 +- .../miapi/materials/crystal/sapphire.json | 4 +- .../miapi/materials/metal/aluminum.json | 64 +++++++++++ .../miapi/materials/metal/constantan.json | 51 +++++++++ .../miapi/materials/metal/electrum.json | 57 ++++++++++ .../miapi/materials/metal/hop_graphite.json | 63 +++++++++++ .../miapi/materials/metal/nickel.json | 52 +++++++++ .../packs/immersiveengineering/pack.mcmeta | 6 + .../materials/crystal/silicon_carbide.json | 4 +- .../materials/crystal/arcane_essence.json | 4 +- .../materials/crystal/cinder_essence.json | 4 +- .../miapi/materials/crystal/fluorite.json | 4 +- tools/generate_materials.py | 21 ++-- tools/materials.py | 105 ++++++++++++++---- 24 files changed, 459 insertions(+), 105 deletions(-) delete mode 100644 src/main/resources/data/c/tags/item/ingots/titanium.json delete mode 100644 src/main/resources/data/c/tags/item/nuggets/titanium.json delete mode 100644 src/main/resources/data/c/tags/item/plates/titanium.json delete mode 100644 src/main/resources/packs/aerospace/pack.mcmeta rename src/main/resources/packs/{aerospace => cosmonautics}/data/cmmodular/miapi/materials/metal/titanium.json (83%) create mode 100644 src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/aluminum.json create mode 100644 src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/constantan.json create mode 100644 src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/electrum.json create mode 100644 src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/hop_graphite.json create mode 100644 src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/nickel.json create mode 100644 src/main/resources/packs/immersiveengineering/pack.mcmeta diff --git a/README.md b/README.md index 4f4ffd2..a2cb4cf 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Create/Mekanism Modular A [Truly Modular](https://modrinth.com/mod/modular-item-api) addon for Minecraft -1.21.1 / NeoForge. It adds 72 materials drawn from Create, Mekanism, Ice and -Fire, Iron's Spells 'n Spellbooks, Create: The Air War, Create: Cosmonautics and -Aeronautics: Interstellar Expansion, so those mods' metals, gems, scales and -essences can be used to build modular tools and armour. +1.21.1 / NeoForge. It adds 77 materials drawn from Create, Mekanism, Ice and +Fire, Immersive Engineering, Iron's Spells 'n Spellbooks, Create: The Air War, +Create: Cosmonautics and Aeronautics: Interstellar Expansion, so those mods' +metals, gems, scales and essences can be used to build modular tools and armour. Every source mod is optional. Install any subset - the materials for mods you do not have are never registered. @@ -22,11 +22,13 @@ and a material whose ingredient item is missing fails to parse. So each source mod's materials are a separate built-in datapack, registered in `CMModular.java` only when that mod is present. -Titanium is the exception: Air War and Cosmonautics both add a titanium ingot, -so one material covers both and draws its ingredients from `c:ingots/titanium` -rather than an item id. Cosmonautics already declares that tag; the tag files in -`data/c/` fill it in for Air War, which ships no common tags, using optional -entries so a missing mod is not an error. +**Overlapping metals.** Several metals come from more than one mod - steel, +lead and uranium from Mekanism and Immersive Engineering, silver from Ice and +Fire and Immersive Engineering, titanium from both aerospace addons. Each one +picks a single provider rather than accepting either, so the crafting screen +shows one entry per metal instead of two identical-looking ones. Providers are +Mekanism for steel/lead/uranium, Ice and Fire for silver, Cosmonautics for +titanium; swapping one is a one-line change in `tools/materials.py`. **Fire immunity.** Cinder essence grants immunity to fire, which is not an attribute the game has and not a property MIAPI offers. Instead of coupling to @@ -115,3 +117,9 @@ Requires `pillow` and `numpy`. - Interstellar Expansion is mostly machinery. Only three of its items are a material rather than a component; solid E-710 is left out because it is rocket fuel. +- Gem sockets do not check the `gem` group. Arsenal gates melee gems on + `gem_melee` and Armory gates armour gems on `gem_armor`, so every gem-like + material carries both and fits any gem slot. +- Immersive Engineering contributes aluminium, nickel, constantan, electrum and + graphite. Its steel, lead, uranium and silver are not separate materials - see + overlapping metals above. diff --git a/src/main/java/eu/abdelbaki/cmmodular/CMModular.java b/src/main/java/eu/abdelbaki/cmmodular/CMModular.java index cdefb4a..070e6bc 100644 --- a/src/main/java/eu/abdelbaki/cmmodular/CMModular.java +++ b/src/main/java/eu/abdelbaki/cmmodular/CMModular.java @@ -13,8 +13,8 @@ import net.neoforged.fml.common.Mod; import net.neoforged.neoforge.event.AddPackFindersEvent; /** - * Adds the materials of Create, Mekanism, Ice and Fire, Iron's Spells and the - * Create aerospace addons to Truly Modular. + * Adds the materials of Create, Mekanism, Ice and Fire, Immersive Engineering, + * Iron's Spells and the Create aerospace addons to Truly Modular. * *

Almost all of this mod is data. The one thing data cannot do is load * conditionally: MIAPI reads materials with its own loader, which honours @@ -22,28 +22,21 @@ import net.neoforged.neoforge.event.AddPackFindersEvent; * file off, and a material whose ingredient item does not exist fails to parse * outright. So each source mod's materials live in their own built-in datapack * and only get registered when that mod is actually installed. + * + *

Where two mods add the same metal - steel, lead and uranium are in both + * Mekanism and Immersive Engineering, silver in both Ice and Fire and Immersive + * Engineering, titanium in both aerospace addons - one of them is simply picked + * as the provider rather than the material accepting either. That keeps one + * entry per metal in the crafting screen. */ @Mod(CMModular.MOD_ID) public class CMModular { public static final String MOD_ID = "cmmodular"; - /** - * A set of materials, and the mods it needs in order to load. - * - * @param anyOf when true one of {@code requires} is enough, rather than all - * of them. Such a pack cannot name items directly - it has no - * way to know which mod turned up - so it sources ingredients - * from item tags instead. - */ - private record MaterialPack(String id, String name, List requires, boolean anyOf) { - MaterialPack(String id, String name, String... requires) { - this(id, name, List.of(requires), false); - } - + /** A set of materials, and the mod it needs in order to load. */ + private record MaterialPack(String id, String name, String requires) { boolean present() { - return anyOf - ? requires.stream().anyMatch(ModList.get()::isLoaded) - : requires.stream().allMatch(ModList.get()::isLoaded); + return ModList.get().isLoaded(requires); } } @@ -51,14 +44,12 @@ public class CMModular { new MaterialPack("mekanism", "Mekanism Materials", "mekanism"), new MaterialPack("create", "Create Materials", "create"), new MaterialPack("iceandfire", "Ice and Fire Materials", "iceandfire"), + new MaterialPack("immersiveengineering", "Immersive Engineering Materials", + "immersiveengineering"), new MaterialPack("irons_spellbooks", "Iron's Spells Materials", "irons_spellbooks"), new MaterialPack("interstellar", "Interstellar Expansion Materials", "vsie"), new MaterialPack("air_war", "Create: The Air War Materials", "create_the_air_wars"), - new MaterialPack("cosmonautics", "Create: Cosmonautics Materials", "rocketnautics"), - // Both aerospace addons add a titanium ingot. One material covers - // them both, fed by the c:ingots/titanium tag. - new MaterialPack("aerospace", "Aerospace Materials", - List.of("create_the_air_wars", "rocketnautics"), true)); + new MaterialPack("cosmonautics", "Create: Cosmonautics Materials", "rocketnautics")); public CMModular(IEventBus modBus) { FireImmunity.register(modBus); diff --git a/src/main/resources/META-INF/neoforge.mods.toml b/src/main/resources/META-INF/neoforge.mods.toml index 41705e4..f6c71ae 100644 --- a/src/main/resources/META-INF/neoforge.mods.toml +++ b/src/main/resources/META-INF/neoforge.mods.toml @@ -71,6 +71,13 @@ versionRange = "[0,)" ordering = "AFTER" side = "BOTH" +[[dependencies.${mod_id}]] +modId = "immersiveengineering" +type = "optional" +versionRange = "[0,)" +ordering = "AFTER" +side = "BOTH" + [[dependencies.${mod_id}]] modId = "vsie" type = "optional" diff --git a/src/main/resources/data/c/tags/item/ingots/titanium.json b/src/main/resources/data/c/tags/item/ingots/titanium.json deleted file mode 100644 index 8ed2dba..0000000 --- a/src/main/resources/data/c/tags/item/ingots/titanium.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "replace": false, - "values": [ - { - "id": "create_the_air_wars:titaniumingot", - "required": false - } - ] -} diff --git a/src/main/resources/data/c/tags/item/nuggets/titanium.json b/src/main/resources/data/c/tags/item/nuggets/titanium.json deleted file mode 100644 index 02cf2f7..0000000 --- a/src/main/resources/data/c/tags/item/nuggets/titanium.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "replace": false, - "values": [ - { - "id": "create_the_air_wars:titaniumnugget", - "required": false - } - ] -} diff --git a/src/main/resources/data/c/tags/item/plates/titanium.json b/src/main/resources/data/c/tags/item/plates/titanium.json deleted file mode 100644 index 0a9b381..0000000 --- a/src/main/resources/data/c/tags/item/plates/titanium.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "replace": false, - "values": [ - { - "id": "create_the_air_wars:titaniumsheet", - "required": false - } - ] -} diff --git a/src/main/resources/packs/aerospace/pack.mcmeta b/src/main/resources/packs/aerospace/pack.mcmeta deleted file mode 100644 index 13f0382..0000000 --- a/src/main/resources/packs/aerospace/pack.mcmeta +++ /dev/null @@ -1,6 +0,0 @@ -{ - "pack": { - "description": "Aerospace Materials for Truly Modular", - "pack_format": 48 - } -} diff --git a/src/main/resources/packs/air_war/data/cmmodular/miapi/materials/crystal/sulfur.json b/src/main/resources/packs/air_war/data/cmmodular/miapi/materials/crystal/sulfur.json index f6bc983..5c20d56 100644 --- a/src/main/resources/packs/air_war/data/cmmodular/miapi/materials/crystal/sulfur.json +++ b/src/main/resources/packs/air_war/data/cmmodular/miapi/materials/crystal/sulfur.json @@ -1,7 +1,9 @@ { "translation": "Sulfur ", "groups": [ - "crystal" + "crystal", + "gem_melee", + "gem_armor" ], "icon": { "type": "item", diff --git a/src/main/resources/packs/aerospace/data/cmmodular/miapi/materials/metal/titanium.json b/src/main/resources/packs/cosmonautics/data/cmmodular/miapi/materials/metal/titanium.json similarity index 83% rename from src/main/resources/packs/aerospace/data/cmmodular/miapi/materials/metal/titanium.json rename to src/main/resources/packs/cosmonautics/data/cmmodular/miapi/materials/metal/titanium.json index 1ba36b8..69c7211 100644 --- a/src/main/resources/packs/aerospace/data/cmmodular/miapi/materials/metal/titanium.json +++ b/src/main/resources/packs/cosmonautics/data/cmmodular/miapi/materials/metal/titanium.json @@ -52,16 +52,20 @@ }, "items": [ { - "tag": "c:ingots/titanium", + "item": "rocketnautics:titanium_ingot", "value": 1.0 }, { - "tag": "c:nuggets/titanium", + "item": "rocketnautics:titanium_nugget", "value": 0.11112 }, { - "tag": "c:plates/titanium", + "item": "rocketnautics:titanium_sheet", "value": 1.0 + }, + { + "item": "rocketnautics:titanium_block", + "value": 9.0 } ] } diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/crystal/dread_shard.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/crystal/dread_shard.json index 262151b..59ff06c 100644 --- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/crystal/dread_shard.json +++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/crystal/dread_shard.json @@ -2,7 +2,9 @@ "translation": "Dread ", "groups": [ "crystal", - "metal" + "metal", + "gem_melee", + "gem_armor" ], "icon": { "type": "item", diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/crystal/pixie_dust.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/crystal/pixie_dust.json index 8c250c1..c481514 100644 --- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/crystal/pixie_dust.json +++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/crystal/pixie_dust.json @@ -1,7 +1,9 @@ { "translation": "Pixie Dust ", "groups": [ - "crystal" + "crystal", + "gem_melee", + "gem_armor" ], "icon": { "type": "item", diff --git a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/crystal/sapphire.json b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/crystal/sapphire.json index 52d4868..cb5fd56 100644 --- a/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/crystal/sapphire.json +++ b/src/main/resources/packs/iceandfire/data/cmmodular/miapi/materials/crystal/sapphire.json @@ -2,7 +2,9 @@ "translation": "Sapphire ", "groups": [ "crystal", - "gem" + "gem", + "gem_melee", + "gem_armor" ], "icon": { "type": "item", diff --git a/src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/aluminum.json b/src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/aluminum.json new file mode 100644 index 0000000..7494f48 --- /dev/null +++ b/src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/aluminum.json @@ -0,0 +1,64 @@ +{ + "translation": "Aluminium ", + "groups": [ + "metal" + ], + "icon": { + "type": "item", + "item": "immersiveengineering:ingot_aluminum" + }, + "hardness": 4.0, + "density": 1.2, + "flexibility": 3, + "durability": 260, + "enchantability": 17, + "toughness": 0, + "tier": 3, + "mining_speed": 6, + "mining_level": "minecraft:incorrect_for_iron_tool", + "armor_durability": 14, + "color": "B9C0C3", + "color_palette": { + "type": "grayscale_map", + "colors": { + "24": "3c3d3e", + "68": "737677", + "107": "7a7e7f", + "150": "818587", + "190": "93989a", + "216": "b9c0c3", + "255": "c5cdd0" + }, + "filler": "interpolate" + }, + "textures": [ + "metallic", + "bright" + ], + "properties": { + "handheld": { + "attributes": [ + { + "attribute": "generic.attack_speed", + "value": "0.1", + "operation": "+", + "slot": "mainhand" + } + ] + } + }, + "items": [ + { + "item": "immersiveengineering:ingot_aluminum", + "value": 1.0 + }, + { + "item": "immersiveengineering:nugget_aluminum", + "value": 0.11112 + }, + { + "item": "immersiveengineering:plate_aluminum", + "value": 1.0 + } + ] +} diff --git a/src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/constantan.json b/src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/constantan.json new file mode 100644 index 0000000..9505657 --- /dev/null +++ b/src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/constantan.json @@ -0,0 +1,51 @@ +{ + "translation": "Constantan ", + "groups": [ + "metal" + ], + "icon": { + "type": "item", + "item": "immersiveengineering:ingot_constantan" + }, + "hardness": 5.6, + "density": 4.0, + "flexibility": 2, + "durability": 640, + "enchantability": 14, + "toughness": 2, + "tier": 4, + "mining_speed": 7, + "mining_level": "minecraft:incorrect_for_diamond_tool", + "armor_durability": 24, + "color": "FE8E70", + "color_palette": { + "type": "grayscale_map", + "colors": { + "24": "321c16", + "68": "60352a", + "107": "733e32", + "150": "7f4537", + "190": "aa5c4a", + "216": "fe8e70", + "255": "ff9f7e" + }, + "filler": "interpolate" + }, + "textures": [ + "metallic" + ], + "items": [ + { + "item": "immersiveengineering:ingot_constantan", + "value": 1.0 + }, + { + "item": "immersiveengineering:nugget_constantan", + "value": 0.11112 + }, + { + "item": "immersiveengineering:plate_constantan", + "value": 1.0 + } + ] +} diff --git a/src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/electrum.json b/src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/electrum.json new file mode 100644 index 0000000..ad58f88 --- /dev/null +++ b/src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/electrum.json @@ -0,0 +1,57 @@ +{ + "translation": "Electrum ", + "groups": [ + "metal" + ], + "icon": { + "type": "item", + "item": "immersiveengineering:ingot_electrum" + }, + "hardness": 4.4, + "density": 3.6, + "flexibility": 2, + "durability": 260, + "enchantability": 26, + "toughness": 0, + "tier": 3, + "mining_speed": 9, + "mining_level": "minecraft:incorrect_for_iron_tool", + "armor_durability": 14, + "color": "FFBC4C", + "color_palette": { + "type": "grayscale_map", + "colors": { + "24": "362a17", + "68": "67512c", + "107": "785c30", + "150": "7d5f31", + "190": "b0833b", + "216": "ffbc4c", + "255": "ffd051" + }, + "filler": "interpolate" + }, + "textures": [ + "metallic", + "bright" + ], + "properties": { + "tool": { + "luminious_learning": "0.5" + } + }, + "items": [ + { + "item": "immersiveengineering:ingot_electrum", + "value": 1.0 + }, + { + "item": "immersiveengineering:nugget_electrum", + "value": 0.11112 + }, + { + "item": "immersiveengineering:plate_electrum", + "value": 1.0 + } + ] +} diff --git a/src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/hop_graphite.json b/src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/hop_graphite.json new file mode 100644 index 0000000..bb944a6 --- /dev/null +++ b/src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/hop_graphite.json @@ -0,0 +1,63 @@ +{ + "translation": "Graphite ", + "groups": [ + "metal" + ], + "icon": { + "type": "item", + "item": "immersiveengineering:ingot_hop_graphite" + }, + "hardness": 4.2, + "density": 2.0, + "flexibility": 1, + "durability": 520, + "enchantability": 12, + "toughness": 2, + "tier": 4, + "mining_speed": 10, + "mining_level": "minecraft:incorrect_for_diamond_tool", + "armor_durability": 18, + "color": "373737", + "color_palette": { + "type": "grayscale_map", + "colors": { + "24": "080808", + "68": "101010", + "107": "121212", + "150": "171717", + "190": "212121", + "216": "373737", + "255": "3f3f3f" + }, + "filler": "interpolate" + }, + "textures": [ + "rough", + "metallic" + ], + "properties": { + "default": { + "fire_proof": true + }, + "handheld": { + "attributes": [ + { + "attribute": "generic.attack_speed", + "value": "0.08", + "operation": "+", + "slot": "mainhand" + } + ] + } + }, + "items": [ + { + "item": "immersiveengineering:ingot_hop_graphite", + "value": 1.0 + }, + { + "item": "immersiveengineering:plate_hop_graphite", + "value": 1.0 + } + ] +} diff --git a/src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/nickel.json b/src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/nickel.json new file mode 100644 index 0000000..586d6d9 --- /dev/null +++ b/src/main/resources/packs/immersiveengineering/data/cmmodular/miapi/materials/metal/nickel.json @@ -0,0 +1,52 @@ +{ + "translation": "Nickel ", + "groups": [ + "metal" + ], + "icon": { + "type": "item", + "item": "immersiveengineering:ingot_nickel" + }, + "hardness": 5.4, + "density": 4.4, + "flexibility": 1, + "durability": 480, + "enchantability": 10, + "toughness": 1, + "tier": 3, + "mining_speed": 6, + "mining_level": "minecraft:incorrect_for_iron_tool", + "armor_durability": 20, + "armor_toughness": 0.5, + "color": "C8CEBD", + "color_palette": { + "type": "grayscale_map", + "colors": { + "24": "2b2c28", + "68": "52544d", + "107": "60635a", + "150": "686c62", + "190": "878c80", + "216": "c8cebd", + "255": "dfe5d2" + }, + "filler": "interpolate" + }, + "textures": [ + "metallic" + ], + "items": [ + { + "item": "immersiveengineering:ingot_nickel", + "value": 1.0 + }, + { + "item": "immersiveengineering:nugget_nickel", + "value": 0.11112 + }, + { + "item": "immersiveengineering:plate_nickel", + "value": 1.0 + } + ] +} diff --git a/src/main/resources/packs/immersiveengineering/pack.mcmeta b/src/main/resources/packs/immersiveengineering/pack.mcmeta new file mode 100644 index 0000000..306c99a --- /dev/null +++ b/src/main/resources/packs/immersiveengineering/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "Immersive Engineering Materials for Truly Modular", + "pack_format": 48 + } +} diff --git a/src/main/resources/packs/interstellar/data/cmmodular/miapi/materials/crystal/silicon_carbide.json b/src/main/resources/packs/interstellar/data/cmmodular/miapi/materials/crystal/silicon_carbide.json index b53d69c..082eca0 100644 --- a/src/main/resources/packs/interstellar/data/cmmodular/miapi/materials/crystal/silicon_carbide.json +++ b/src/main/resources/packs/interstellar/data/cmmodular/miapi/materials/crystal/silicon_carbide.json @@ -1,7 +1,9 @@ { "translation": "Silicon Carbide ", "groups": [ - "crystal" + "crystal", + "gem_melee", + "gem_armor" ], "icon": { "type": "item", diff --git a/src/main/resources/packs/irons_spellbooks/data/cmmodular/miapi/materials/crystal/arcane_essence.json b/src/main/resources/packs/irons_spellbooks/data/cmmodular/miapi/materials/crystal/arcane_essence.json index b45fd24..7e2777b 100644 --- a/src/main/resources/packs/irons_spellbooks/data/cmmodular/miapi/materials/crystal/arcane_essence.json +++ b/src/main/resources/packs/irons_spellbooks/data/cmmodular/miapi/materials/crystal/arcane_essence.json @@ -2,7 +2,9 @@ "translation": "Arcane ", "groups": [ "crystal", - "gem" + "gem", + "gem_melee", + "gem_armor" ], "icon": { "type": "item", diff --git a/src/main/resources/packs/irons_spellbooks/data/cmmodular/miapi/materials/crystal/cinder_essence.json b/src/main/resources/packs/irons_spellbooks/data/cmmodular/miapi/materials/crystal/cinder_essence.json index 898734a..458dc4d 100644 --- a/src/main/resources/packs/irons_spellbooks/data/cmmodular/miapi/materials/crystal/cinder_essence.json +++ b/src/main/resources/packs/irons_spellbooks/data/cmmodular/miapi/materials/crystal/cinder_essence.json @@ -2,7 +2,9 @@ "translation": "Cinder ", "groups": [ "crystal", - "gem" + "gem", + "gem_melee", + "gem_armor" ], "icon": { "type": "item", diff --git a/src/main/resources/packs/mekanism/data/cmmodular/miapi/materials/crystal/fluorite.json b/src/main/resources/packs/mekanism/data/cmmodular/miapi/materials/crystal/fluorite.json index 5192bd9..b1e2c35 100644 --- a/src/main/resources/packs/mekanism/data/cmmodular/miapi/materials/crystal/fluorite.json +++ b/src/main/resources/packs/mekanism/data/cmmodular/miapi/materials/crystal/fluorite.json @@ -2,7 +2,9 @@ "translation": "Fluorite ", "groups": [ "crystal", - "gem" + "gem", + "gem_melee", + "gem_armor" ], "icon": { "type": "item", diff --git a/tools/generate_materials.py b/tools/generate_materials.py index 9208e51..71a5c0d 100644 --- a/tools/generate_materials.py +++ b/tools/generate_materials.py @@ -18,6 +18,7 @@ rather than shipping a material that silently refuses to load. import argparse import json import re +import shutil import sys import zipfile @@ -185,18 +186,13 @@ def build_material(spec, jars: Jars): return out -def check_items(spec, jars: Jars, any_of_pack: bool): - """Item ids must exist; tags are allowed to be missing at build time.""" +def check_items(spec, jars: Jars): + """Every item a material names has to exist in the jar that provides it.""" problems = [] for entry in spec["items"]: if "item" not in entry: continue - if any_of_pack: - problems.append( - f"{spec['name']}: pack '{spec['pack']}' loads when any one of its " - f"mods is present, so it must use tags, not the item id {entry['item']}" - ) - elif not jars.has_item(entry["item"]): + if not jars.has_item(entry["item"]): problems.append(f"{spec['name']}: no such item {entry['item']}") if not jars.has_item(spec["icon"]): problems.append(f"{spec['name']}: icon item {spec['icon']} does not exist") @@ -218,14 +214,19 @@ def main(): problems = [] for spec in MATERIALS: - pack = PACKS[spec["pack"]] - problems += check_items(spec, jars, pack.get("any_of", False)) + problems += check_items(spec, jars) if problems: print("aborting, item ids do not check out:", file=sys.stderr) for p in problems: print(" " + p, file=sys.stderr) return 1 + # Wipe first. A material that moves between packs would otherwise leave a + # stale copy behind, and two files claiming the same material id is a silent + # mess to debug. + if args.out.exists(): + shutil.rmtree(args.out) + written = 0 for pack_id, pack in PACKS.items(): root = args.out / pack_id diff --git a/tools/materials.py b/tools/materials.py index 6261555..92627a8 100644 --- a/tools/materials.py +++ b/tools/materials.py @@ -39,22 +39,19 @@ NUGGET = 0.11112 # 1/9, matching MIAPI's own nugget values BLOCK = 9.0 # Sub-packs. Each becomes a NeoForge built-in datapack that is only registered -# when its `mods` are present, so a material never references a missing item. -# `any_of` packs load when at least one listed mod is installed; those materials -# therefore have to source their ingredients from tags, not item ids. +# when its mod is present, so a material never references a missing item. +# Where two mods add the same metal, one is picked as the provider and the +# material lives in that mod's pack - see the Immersive Engineering section. PACKS = { - "mekanism": {"mods": ["mekanism"], "name": "Mekanism Materials"}, - "create": {"mods": ["create"], "name": "Create Materials"}, - "iceandfire": {"mods": ["iceandfire"], "name": "Ice and Fire Materials"}, - "air_war": {"mods": ["create_the_air_wars"], "name": "Create: The Air War Materials"}, - "cosmonautics": {"mods": ["rocketnautics"], "name": "Create: Cosmonautics Materials"}, - "irons_spellbooks": {"mods": ["irons_spellbooks"], "name": "Iron's Spells Materials"}, - "interstellar": {"mods": ["vsie"], "name": "Interstellar Expansion Materials"}, - "aerospace": { - "mods": ["create_the_air_wars", "rocketnautics"], - "any_of": True, - "name": "Aerospace Materials", - }, + "mekanism": {"mod": "mekanism", "name": "Mekanism Materials"}, + "create": {"mod": "create", "name": "Create Materials"}, + "iceandfire": {"mod": "iceandfire", "name": "Ice and Fire Materials"}, + "air_war": {"mod": "create_the_air_wars", "name": "Create: The Air War Materials"}, + "cosmonautics": {"mod": "rocketnautics", "name": "Create: Cosmonautics Materials"}, + "irons_spellbooks": {"mod": "irons_spellbooks", "name": "Iron's Spells Materials"}, + "interstellar": {"mod": "vsie", "name": "Interstellar Expansion Materials"}, + "immersiveengineering": {"mod": "immersiveengineering", + "name": "Immersive Engineering Materials"}, } # Attribute this mod registers itself, so a material can grant something the @@ -110,6 +107,7 @@ def ingots(mod, ingot, nugget=None, block=None, extra=()): return out + def speed(value): """Attack speed tweak on held modules: positive is faster.""" return {"attributes": [{"attribute": "generic.attack_speed", "value": str(value), @@ -295,10 +293,11 @@ MATERIALS = [ # ----------------------------------------------------------------- Aerospace # Both Air War and Cosmonautics add titanium. This is one material fed by # tags so either mod (or both) supplies it; see the c: tag files. - M("titanium", "aerospace", "metal", "Titanium", "rocketnautics:titanium_ingot", - [{"tag": "c:ingots/titanium", "value": 1.0}, - {"tag": "c:nuggets/titanium", "value": NUGGET}, - {"tag": "c:plates/titanium", "value": 1.0}], + M("titanium", "cosmonautics", "metal", "Titanium", "rocketnautics:titanium_ingot", + [{"item": "rocketnautics:titanium_ingot", "value": 1.0}, + {"item": "rocketnautics:titanium_nugget", "value": NUGGET}, + {"item": "rocketnautics:titanium_sheet", "value": 1.0}, + {"item": "rocketnautics:titanium_block", "value": BLOCK}], tier=4, hardness=5.8, density=1.6, flexibility=3, durability=1150, enchantability=11, mining_speed=9, toughness=2, armor_durability=32, armor_toughness=1.5, @@ -552,6 +551,60 @@ MATERIALS = [ properties={"handheld": {"attributes": [ attribute("irons_spellbooks:spell_power", 0.05, "mainhand", "*")]}}), + # ------------------------------------------------- Immersive Engineering + # Steel, lead, uranium and silver are not here - Immersive Engineering adds + # those too, so they live in the tag-fed shared packs above and accept + # either mod's ingots. + M("aluminum", "immersiveengineering", "metal", "Aluminium", + "immersiveengineering:ingot_aluminum", + ingots("immersiveengineering", "ingot_aluminum", "nugget_aluminum", + extra=[{"item": "immersiveengineering:plate_aluminum", "value": 1.0}]), + tier=3, hardness=4.0, density=1.2, flexibility=3, durability=260, + enchantability=17, mining_speed=6, armor_durability=14, + textures=("metallic", "bright"), properties={"handheld": speed(0.10)}), + # Light and corrosion-proof but soft - the cheap way to a fast tool, at + # the cost of everything else. + + M("nickel", "immersiveengineering", "metal", "Nickel", + "immersiveengineering:ingot_nickel", + ingots("immersiveengineering", "ingot_nickel", "nugget_nickel", + extra=[{"item": "immersiveengineering:plate_nickel", "value": 1.0}]), + tier=3, hardness=5.4, density=4.4, flexibility=1, durability=480, + enchantability=10, mining_speed=6, toughness=1, armor_durability=20, + armor_toughness=0.5), + # Hard, tough and stubbornly corrosion resistant; dull to enchant. + + M("constantan", "immersiveengineering", "metal", "Constantan", + "immersiveengineering:ingot_constantan", + ingots("immersiveengineering", "ingot_constantan", "nugget_constantan", + extra=[{"item": "immersiveengineering:plate_constantan", "value": 1.0}]), + tier=4, hardness=5.6, density=4.0, flexibility=2, durability=640, + enchantability=14, mining_speed=7, toughness=2, armor_durability=24), + # A copper-nickel alloy prized for not changing under heat or strain, + # so it is the steady middle option: no weakness, no standout. + + M("electrum", "immersiveengineering", "metal", "Electrum", + "immersiveengineering:ingot_electrum", + ingots("immersiveengineering", "ingot_electrum", "nugget_electrum", + extra=[{"item": "immersiveengineering:plate_electrum", "value": 1.0}]), + tier=3, hardness=4.4, density=3.6, flexibility=2, durability=260, + enchantability=26, mining_speed=9, armor_durability=14, + textures=("metallic", "bright"), + properties={"tool": {"luminious_learning": "0.5"}}), + # Gold-silver alloy, so it inherits gold's bargain: superb to enchant, + # falls apart quickly. + + M("hop_graphite", "immersiveengineering", "metal", "Graphite", + "immersiveengineering:ingot_hop_graphite", + ingots("immersiveengineering", "ingot_hop_graphite", None, + extra=[{"item": "immersiveengineering:plate_hop_graphite", "value": 1.0}]), + tier=4, hardness=4.2, density=2.0, flexibility=1, durability=520, + enchantability=12, mining_speed=10, toughness=2, armor_durability=18, + textures=("rough", "metallic"), + properties={"default": {"fire_proof": True}, "handheld": speed(0.08)}), + # Graphite is a dry lubricant and shrugs off heat, hence the quick swing, + # high mining speed and fireproofing - but it is soft, so it hits weakly. + # --------------------------------- Aeronautics: Interstellar Expansion (vsie) # Mostly a machinery mod; these are the three items that are a material # rather than a component. Solid E-710 is deliberately left out - it is @@ -671,6 +724,20 @@ def _scales(): MATERIALS.extend(_scales()) +# Gem sockets do not look for the "gem" group. Truly Modular: Arsenal gates its +# melee gem modules on `gem_melee` and Armory gates its armour ones on +# `gem_armor`, so a material tagged only "crystal"/"gem" is rejected by every +# socket - which is exactly what happened to the two essences. Anything gem-like +# gets both, so it fits any gem slot regardless of size or whether the item is +# a weapon or a piece of armour. +GEM_SOCKET_GROUPS = ("gem_melee", "gem_armor") + +for _material in MATERIALS: + if {"gem", "crystal"} & set(_material["groups"]): + _material["groups"] = list(_material["groups"]) + [ + g for g in GEM_SOCKET_GROUPS if g not in _material["groups"]] + + # Extensions add data to a material that already exists rather than replacing it. # Ice and Fire's amethyst is the same stone MIAPI already ships, so it just # becomes another way to craft it.