Support MaterialLib ml references in meteor configs

This commit is contained in:
Ruling-0 committed 2026-08-17 20:19:51 -05:00
1 parent c99578e04d
commit 421478e6fa
6 files changed
+112 -4

No files matched your search

@@ -3355,6 +3355,7 @@ public class AlchemicalWizardry {
MeteorRegistry.loadConfig();
MeteorReagentRegistry.loadConfig();
MeteorRegistry.logMaterialLibTally();
this.initCompressionHandlers();
}
@@ -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(
@@ -22,6 +22,19 @@ class ItemStackAdapter extends TypeAdapter<ItemStack> {
.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);
@@ -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> 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> reagent) {
this.itemStack = stack;
this.materialName = null;
this.shapeToken = null;
this.weight = weight;
this.reagent = reagent;
}
/// The default meteor block named as `ml:<Material>:<shape>`, 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<MeteorComponent> parseStringArray(String[] blockArray) {
List<MeteorComponent> 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<Reagent> 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;
}
@@ -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<Meteor> meteorList = new ArrayList<>();
private static int materialLibResolved;
private static int materialLibInvalid;
/// The stack a `ml:<Material>:<shape>` 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())
@@ -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);
}
}