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.