From 421478e6fa5ccbc918f190ce5e5fe4fbfc072fe4 Mon Sep 17 00:00:00 2001 From: Ruling-0 <47913168+Ruling-0@users.noreply.github.com> Date: Mon, 17 Aug 2026 20:17:35 -0500 Subject: [PATCH] Support MaterialLib ml references in meteor configs --- .../AlchemicalWizardry.java | 1 + .../BloodMagicConfiguration.java | 2 +- .../summoning/meteor/ItemStackAdapter.java | 13 +++++ .../summoning/meteor/MeteorComponent.java | 49 +++++++++++++++++-- .../summoning/meteor/MeteorRegistry.java | 31 ++++++++++++ .../compat/materiallib/MaterialLibStacks.java | 20 ++++++++ 6 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 src/main/java/WayofTime/alchemicalWizardry/compat/materiallib/MaterialLibStacks.java diff --git a/src/main/java/WayofTime/alchemicalWizardry/AlchemicalWizardry.java b/src/main/java/WayofTime/alchemicalWizardry/AlchemicalWizardry.java index b0476f2d..54f38fd5 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/AlchemicalWizardry.java +++ b/src/main/java/WayofTime/alchemicalWizardry/AlchemicalWizardry.java @@ -3355,6 +3355,7 @@ public class AlchemicalWizardry { MeteorRegistry.loadConfig(); MeteorReagentRegistry.loadConfig(); + MeteorRegistry.logMaterialLibTally(); this.initCompressionHandlers(); } diff --git a/src/main/java/WayofTime/alchemicalWizardry/BloodMagicConfiguration.java b/src/main/java/WayofTime/alchemicalWizardry/BloodMagicConfiguration.java index 282f4f8a..51bd3224 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/BloodMagicConfiguration.java +++ b/src/main/java/WayofTime/alchemicalWizardry/BloodMagicConfiguration.java @@ -114,7 +114,7 @@ public class BloodMagicConfiguration { The block to use for filler in meteors if none is provided in the meteor's config file and that meteor's fillerChance is greater than 0. Also used as a fallback for empty ore lists in meteor configs. Specify the block with the format: - "modId:itemName:meta" + "modId:itemName:meta", or a MaterialLib block with the format "ml:material:shape". Defaults to minecraft:stone:0 if no block is provided or the provided block cannot be found."""); MeteorComponent.setDefaultMeteorBlock(); AlchemicalWizardry.allowedCrushedOresArray = config.get( diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/summoning/meteor/ItemStackAdapter.java b/src/main/java/WayofTime/alchemicalWizardry/common/summoning/meteor/ItemStackAdapter.java index b95f5d8b..454f6266 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/summoning/meteor/ItemStackAdapter.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/summoning/meteor/ItemStackAdapter.java @@ -22,6 +22,19 @@ class ItemStackAdapter extends TypeAdapter { .warn("Unable to read item stack \"{}\". Valid format is \"modid:name(:meta optional)\"", str); return null; } + if (input[0].equals("ml")) { + if (input.length != 3) { + AlchemicalWizardry.logger.warn( + "Unable to read item stack \"{}\". Valid MaterialLib format is \"ml:material:shape\"", + str); + return null; + } + ItemStack resolved = MeteorRegistry.resolveMaterialLibStack(input[1], input[2]); + if (resolved == null) { + AlchemicalWizardry.logger.warn("Unable to find item stack \"{}\".", str); + } + return resolved; + } ItemStack itemStack = GameRegistry.findItemStack(input[0], input[1], 1); if (itemStack == null) { AlchemicalWizardry.logger.warn("Unable to find item stack \"{}\".", str); diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/summoning/meteor/MeteorComponent.java b/src/main/java/WayofTime/alchemicalWizardry/common/summoning/meteor/MeteorComponent.java index 4aa72e53..5936eda8 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/summoning/meteor/MeteorComponent.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/summoning/meteor/MeteorComponent.java @@ -18,13 +18,19 @@ import cpw.mods.fml.common.registry.GameRegistry; public class MeteorComponent { private final int weight; - private final ItemStack itemStack; + private ItemStack itemStack; + private final String materialName; + private final String shapeToken; private final ArrayList reagent; public static MeteorComponent defaultMeteorBlock; public static void setDefaultMeteorBlock() { String string = AlchemicalWizardry.defaultMeteorBlock; String[] split = string.split(":"); + if (split.length == 3 && split[0].equals("ml")) { + defaultMeteorBlock = new MeteorComponent(split[1], split[2]); + return; + } ItemStack stack = null; if (!string.isEmpty() && split.length >= 3) { stack = GameRegistry.findItemStack(split[0], split[1], 1); @@ -43,10 +49,22 @@ public class MeteorComponent { public MeteorComponent(ItemStack stack, int weight, ArrayList reagent) { this.itemStack = stack; + this.materialName = null; + this.shapeToken = null; this.weight = weight; this.reagent = reagent; } + /// The default meteor block named as `ml::`, whose stack [#getBlock] resolves on first use: the + /// config it comes from is read at preInit, before MaterialLib resolves its shapes. + private MeteorComponent(String materialName, String shapeToken) { + this.itemStack = null; + this.materialName = materialName; + this.shapeToken = shapeToken; + this.weight = 1; + this.reagent = new ArrayList<>(); + } + public static List parseStringArray(String[] blockArray) { List addList = new ArrayList<>(); if (blockArray == null) { @@ -65,10 +83,25 @@ public class MeteorComponent { private static final Pattern itemNamePattern = Pattern.compile("(.*):(.*):(\\d+):(\\d+)(:.*)?"); // OREDICT:oreDictName:weight(:reagent1, reagent2, ... optional) private static final Pattern oredictPattern = Pattern.compile("OREDICT:(.*):(\\d+)(:.*)?"); + // ml:material:shape:weight(:reagent1, reagent2, ... optional) + private static final Pattern materialLibPattern = Pattern.compile("ml:([^:]+):([^:]+):(\\d+)(:.*)?"); public static MeteorComponent parseString(String blockName) { - Matcher matcher = itemNamePattern.matcher(blockName); + Matcher matcher = materialLibPattern.matcher(blockName); if (matcher.matches()) { + String materialName = matcher.group(1); + String shapeToken = matcher.group(2); + int weight = Integer.parseInt(matcher.group(3)); + String reagent = matcher.group(4); + + ArrayList reagentList = MeteorReagent.parseReagents(reagent, blockName); + + ItemStack stack = MeteorRegistry.resolveMaterialLibStack(materialName, shapeToken); + if (stack != null && stack.getItem() instanceof ItemBlock) { + return new MeteorComponent(stack, weight, reagentList); + } + + } else if ((matcher = itemNamePattern.matcher(blockName)).matches()) { String modID = matcher.group(1); String itemName = matcher.group(2); int meta = Integer.parseInt(matcher.group(3)); @@ -100,7 +133,7 @@ public class MeteorComponent { } AlchemicalWizardry.logger.warn("Unable to add Meteor Component \"{}\"", blockName); AlchemicalWizardry.logger.warn( - "Valid formats are \"modId:itemName:meta:weight(:reagent1, reagent2, ... optional)\" and \"OREDICT:oreDictName:weight(:reagent1, reagent2, ... optional)\"."); + "Valid formats are \"modId:itemName:meta:weight(:reagent1, reagent2, ... optional)\", \"OREDICT:oreDictName:weight(:reagent1, reagent2, ... optional)\" and \"ml:material:shape:weight(:reagent1, reagent2, ... optional)\"."); return null; } @@ -117,6 +150,16 @@ public class MeteorComponent { } public ItemStack getBlock() { + if (itemStack == null && materialName != null) { + itemStack = MeteorRegistry.resolveMaterialLibStack(materialName, shapeToken); + if (itemStack == null || !(itemStack.getItem() instanceof ItemBlock)) { + AlchemicalWizardry.logger.warn( + "Unable to use \"ml:{}:{}\" as the default meteor block, falling back to stone.", + materialName, + shapeToken); + itemStack = new ItemStack(Blocks.stone); + } + } return itemStack; } diff --git a/src/main/java/WayofTime/alchemicalWizardry/common/summoning/meteor/MeteorRegistry.java b/src/main/java/WayofTime/alchemicalWizardry/common/summoning/meteor/MeteorRegistry.java index 02660f17..e491605c 100644 --- a/src/main/java/WayofTime/alchemicalWizardry/common/summoning/meteor/MeteorRegistry.java +++ b/src/main/java/WayofTime/alchemicalWizardry/common/summoning/meteor/MeteorRegistry.java @@ -17,11 +17,42 @@ import com.google.gson.JsonSyntaxException; import WayofTime.alchemicalWizardry.AlchemicalWizardry; import WayofTime.alchemicalWizardry.api.alchemy.energy.Reagent; +import WayofTime.alchemicalWizardry.compat.materiallib.MaterialLibStacks; +import cpw.mods.fml.common.Loader; public class MeteorRegistry { public static List meteorList = new ArrayList<>(); + private static int materialLibResolved; + private static int materialLibInvalid; + + /// The stack a `ml::` entry names, or null when MaterialLib is absent or the entry resolves to + /// nothing. Every resolution is tallied for [#logMaterialLibTally]. + static ItemStack resolveMaterialLibStack(String materialName, String shapeToken) { + ItemStack stack = Loader.isModLoaded("materiallib") ? MaterialLibStacks.getStack(materialName, shapeToken) + : null; + if (stack == null) { + materialLibInvalid++; + } else { + materialLibResolved++; + } + return stack; + } + + /// Logs how many `ml:` entries the meteor and reagent configs resolved, then clears the tally. Call once both + /// have been loaded. + public static void logMaterialLibTally() { + if (materialLibResolved + materialLibInvalid > 0) { + AlchemicalWizardry.logger.info( + "Blood Magic: resolved {} MaterialLib entries ({} invalid)", + materialLibResolved, + materialLibInvalid); + } + materialLibResolved = 0; + materialLibInvalid = 0; + } + public static void loadConfig() { Gson gson = new GsonBuilder().setPrettyPrinting() .registerTypeAdapter(MeteorComponent.class, new MeteorComponentAdapter()) diff --git a/src/main/java/WayofTime/alchemicalWizardry/compat/materiallib/MaterialLibStacks.java b/src/main/java/WayofTime/alchemicalWizardry/compat/materiallib/MaterialLibStacks.java new file mode 100644 index 00000000..c5c319f3 --- /dev/null +++ b/src/main/java/WayofTime/alchemicalWizardry/compat/materiallib/MaterialLibStacks.java @@ -0,0 +1,20 @@ +package WayofTime.alchemicalWizardry.compat.materiallib; + +import net.minecraft.item.ItemStack; + +import com.ruling_0.materiallib.api.StackResolver; + +/// Resolves a MaterialLib item from the material name and shape token a config entry names, for the `ml:` entry forms +/// of the meteor configs. +/// +/// MaterialLib types are named only here, so every caller can gate loading this class on `materiallib` being present. +public final class MaterialLibStacks { + + private MaterialLibStacks() {} + + /// The stack of the named material in the named shape, or null when either name matches nothing or the material + /// does not generate the shape. A miss is logged by MaterialLib. + public static ItemStack getStack(String materialName, String shapeToken) { + return StackResolver.getStack(materialName, shapeToken, 1); + } +}