Compatibility with ae native fluid (#293)

Co-authored-by: lordIcocain <62835225+lordIcocain@users.noreply.github.com>
Co-authored-by: Martin Robertz <dream-master@gmx.net>
Co-authored-by: Kogepan229 <kogepan25629@gmail.com>
This commit is contained in:
authored and GitHub committed 2025-10-04 15:57:41 +00:00
1 parent d49b319954
commit 0d91a7dd43
17 files changed
+228 -1334

No files matched your search

@@ -1,5 +1,7 @@
package com.glodblock.github.client.gui.container.base;
import static appeng.util.Platform.writeStackNBT;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
@@ -25,13 +27,12 @@ import com.glodblock.github.common.item.ItemFluidEncodedPattern;
import com.glodblock.github.common.item.ItemFluidPacket;
import com.glodblock.github.inventory.IPatternConsumer;
import com.glodblock.github.inventory.item.IItemPatternTerminal;
import com.glodblock.github.loader.ItemAndBlockHolder;
import com.glodblock.github.util.FluidPatternDetails;
import com.glodblock.github.util.Util;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
import appeng.api.definitions.IDefinitions;
import appeng.api.implementations.ICraftingPatternItem;
import appeng.api.storage.ITerminalHost;
import appeng.api.storage.data.IAEItemStack;
import appeng.container.guisync.GuiSync;
@@ -43,11 +44,11 @@ import appeng.container.slot.SlotPatternTerm;
import appeng.container.slot.SlotRestrictedInput;
import appeng.helpers.IContainerCraftingPacket;
import appeng.helpers.InventoryAction;
import appeng.items.misc.ItemEncodedPattern;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.tile.inventory.IAEAppEngInventory;
import appeng.tile.inventory.InvOperation;
import appeng.util.Platform;
import appeng.util.item.AEFluidStack;
import appeng.util.item.AEItemStack;
public abstract class FCContainerEncodeTerminal extends ContainerItemMonitor
@@ -172,7 +173,7 @@ public abstract class FCContainerEncodeTerminal extends ContainerItemMonitor
ItemStack is = clickSlot.getStack();
if (is != null && !patternSlotOUT.getHasStack()
&& is.stackSize == 1
&& (is.getItem() instanceof ItemFluidEncodedPattern || is.getItem() instanceof ItemEncodedPattern)) {
&& is.getItem() instanceof ICraftingPatternItem) {
ItemStack output = is.copy();
patternSlotOUT.putStack(output);
p.inventory.setInventorySlotContents(clickSlot.getSlotIndex(), null);
@@ -243,20 +244,6 @@ public abstract class FCContainerEncodeTerminal extends ContainerItemMonitor
return object > 0;
}
protected boolean checkHasFluidPattern() {
if (this.craftingMode) {
return false;
}
boolean hasFluid = containsFluid(this.craftingSlots);
boolean search = nonNullSlot(this.craftingSlots);
if (!search) { // search=false -> inputs were empty
return false;
}
hasFluid |= containsFluid(this.outputSlots);
search = nonNullSlot(this.outputSlots);
return hasFluid && search; // search=false -> outputs were empty
}
protected ItemStack stampAuthor(ItemStack patternStack) {
if (patternStack.stackTagCompound == null) {
patternStack.stackTagCompound = new NBTTagCompound();
@@ -266,13 +253,52 @@ public abstract class FCContainerEncodeTerminal extends ContainerItemMonitor
}
protected void encodeFluidPattern() {
ItemStack patternStack = new ItemStack(ItemAndBlockHolder.PATTERN);
FluidPatternDetails pattern = new FluidPatternDetails(patternStack);
pattern.setInputs(collectInventory(this.craftingSlots));
pattern.setOutputs(collectInventory(this.outputSlots));
pattern.setCanBeSubstitute(this.beSubstitute ? 1 : 0);
pattern.setCombine(this.combine ? 1 : 0);
patternSlotOUT.putStack(stampAuthor(pattern.writeToStack()));
ItemStack patternStack = AEApi.instance().definitions().items().encodedUltimatePattern().maybeStack(1).orNull();
if (patternStack != null) {
final NBTTagCompound encodedValue = new NBTTagCompound();
final ItemStack[] in = this.getInputs();
final ItemStack[] out = this.getOutputs();
final NBTTagList tagIn = new NBTTagList();
final NBTTagList tagOut = new NBTTagList();
for (final ItemStack i : in) {
if (i != null) {
if (i.getItem() instanceof ItemFluidPacket) {
tagIn.appendTag(
writeStackNBT(
AEFluidStack.create(ItemFluidPacket.getFluidStack(i)),
new NBTTagCompound(),
true));
} else {
tagIn.appendTag(writeStackNBT(AEItemStack.create(i), new NBTTagCompound(), true));
}
}
}
for (final ItemStack i : out) {
if (i != null) {
if (i.getItem() instanceof ItemFluidPacket) {
tagOut.appendTag(
writeStackNBT(
AEFluidStack.create(ItemFluidPacket.getFluidStack(i)),
new NBTTagCompound(),
true));
} else {
tagOut.appendTag(writeStackNBT(AEItemStack.create(i), new NBTTagCompound(), true));
}
}
}
encodedValue.setTag("in", tagIn);
encodedValue.setTag("out", tagOut);
encodedValue.setBoolean("substitute", substitute);
encodedValue.setBoolean("beSubstitute", beSubstitute);
encodedValue.setString("author", this.getPlayerInv().player.getCommandSenderName());
patternStack.setTagCompound(encodedValue);
patternSlotOUT.putStack(patternStack);
}
}
protected static IAEItemStack[] collectInventory(Slot[] slots) {
@@ -369,25 +395,27 @@ public abstract class FCContainerEncodeTerminal extends ContainerItemMonitor
}
public void encode() {
fillPattern();
if (!checkHasFluidPattern()) {
encodeItemPattern();
return;
}
ItemStack stack = this.patternSlotOUT.getStack();
if (stack == null) {
stack = this.patternSlotIN.getStack();
if (notPattern(stack)) {
if (getInputs() != null && getOutputs() != null) {
fillPattern();
if (isCraftingMode()) {
encodeItemPattern();
return;
}
if (stack.stackSize == 1) {
this.patternSlotIN.putStack(null);
} else {
stack.stackSize--;
ItemStack stack = this.patternSlotOUT.getStack();
if (stack == null) {
stack = this.patternSlotIN.getStack();
if (notPattern(stack)) {
return;
}
if (stack.stackSize == 1) {
this.patternSlotIN.putStack(null);
} else {
stack.stackSize--;
}
encodeFluidPattern();
} else if (!notPattern(stack)) {
encodeFluidPattern();
}
encodeFluidPattern();
} else if (!notPattern(stack)) {
encodeFluidPattern();
}
}
@@ -396,10 +424,6 @@ public abstract class FCContainerEncodeTerminal extends ContainerItemMonitor
final ItemStack[] in = this.getInputs();
final ItemStack[] out = this.getOutputs();
// if there is no input, this would be silly.
if (in == null || out == null) {
return;
}
// first check the output slots, should either be null, or a pattern
if (output != null && this.notPattern(output)) {
return;
@@ -487,7 +511,10 @@ public abstract class FCContainerEncodeTerminal extends ContainerItemMonitor
boolean isPattern = definitions.items().encodedPattern().isSameAs(output);
isPattern |= definitions.materials().blankPattern().isSameAs(output);
return !isPattern;
boolean isUltimatePattern = definitions.items().encodedUltimatePattern().isSameAs(output);
isUltimatePattern |= definitions.materials().blankPattern().isSameAs(output);
return !isPattern && !isUltimatePattern;
}
protected NBTBase createItemTag(final ItemStack i) {
@@ -569,7 +596,7 @@ public abstract class FCContainerEncodeTerminal extends ContainerItemMonitor
for (Slot s : slots) {
ItemStack st = s.getStack();
if (st == null) continue;
final int count;
final long count;
if (st.getItem() instanceof ItemFluidPacket) {
count = ItemFluidPacket.getFluidAmount(st);
} else {
@@ -1,7 +1,6 @@
package com.glodblock.github.common.item;
import java.util.List;
import java.util.Objects;
import javax.annotation.Nullable;
@@ -23,6 +22,7 @@ import com.glodblock.github.util.NameConst;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IAEItemStack;
import appeng.util.item.AEFluidStack;
import appeng.util.item.AEItemStack;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.relauncher.Side;
@@ -40,11 +40,34 @@ public class ItemFluidPacket extends FCBaseItem {
if (stack == null || !stack.hasTagCompound()) {
return null;
}
FluidStack fluid = FluidStack
.loadFluidStackFromNBT(Objects.requireNonNull(stack.getTagCompound()).getCompoundTag("FluidStack"));
NBTTagCompound tag = stack.getTagCompound().getCompoundTag("FluidStack");
FluidStack fluid = FluidStack.loadFluidStackFromNBT(tag);
if (fluid != null && tag.getLong("Amount") > Integer.MAX_VALUE) fluid.amount = Integer.MAX_VALUE;
return (fluid != null && fluid.amount > 0) ? fluid : null;
}
@Nullable
public static FluidStack getFluidStack(@Nullable IAEItemStack stack) {
return stack != null ? getFluidStack(stack.getItemStack()) : null;
}
@Nullable
public static IAEFluidStack getFluidAEStack(ItemStack stack) {
if (stack != null && stack.hasTagCompound()) {
NBTTagCompound tag = stack.getTagCompound().getCompoundTag("FluidStack");
IAEFluidStack ifs = AEFluidStack.create(FluidStack.loadFluidStackFromNBT(tag));
if (ifs != null && tag.hasKey("Amount")) ifs.setStackSize(tag.getLong("Amount"));
return ifs;
}
return null;
}
@Nullable
public static IAEFluidStack getFluidAEStack(@Nullable IAEItemStack stack) {
return stack != null ? getFluidAEStack(stack.getItemStack()) : null;
}
@Override
public String getUnlocalizedName(ItemStack stack) {
FluidStack fluid = getFluidStack(stack);
@@ -83,25 +106,20 @@ public class ItemFluidPacket extends FCBaseItem {
}
}
@Nullable
public static FluidStack getFluidStack(@Nullable IAEItemStack stack) {
return stack != null ? getFluidStack(stack.getItemStack()) : null;
}
public static void setFluidAmount(ItemStack stack, int amount) {
public static void setFluidAmount(ItemStack stack, long amount) {
if (stack == null || !stack.hasTagCompound()
|| !stack.getTagCompound().hasKey("FluidStack", Constants.NBT.TAG_COMPOUND)) {
return;
}
stack.getTagCompound().getCompoundTag("FluidStack").setInteger("Amount", amount);
stack.getTagCompound().getCompoundTag("FluidStack").setLong("Amount", amount);
}
public static int getFluidAmount(ItemStack stack) {
public static long getFluidAmount(ItemStack stack) {
if (stack == null || !stack.hasTagCompound()) {
return 0;
}
// Default to 0 if no tag exists
return stack.getTagCompound().getCompoundTag("FluidStack").getInteger("Amount");
return stack.getTagCompound().getCompoundTag("FluidStack").getLong("Amount");
}
@Nullable
@@ -120,10 +138,22 @@ public class ItemFluidPacket extends FCBaseItem {
@Nullable
public static ItemStack newStack(@Nullable IAEFluidStack fluid) {
if (fluid == null || fluid.getStackSize() == 0) {
return null;
if (fluid != null && fluid.getStackSize() > 0) {
ItemStack stack = new ItemStack(ItemAndBlockHolder.PACKET);
NBTTagCompound tag = new NBTTagCompound();
NBTTagCompound fluidTag = new NBTTagCompound();
fluid.getFluidStack().writeToNBT(fluidTag);
fluidTag.setLong("Amount", fluid.getStackSize());
tag.setTag("FluidStack", fluidTag);
stack.setTagCompound(tag);
return stack;
}
return newStack(fluid.getFluidStack());
return null;
}
@Nullable
public static IAEItemStack newAeStack(@Nullable FluidStack fluid) {
return AEItemStack.create(newStack(fluid));
}
@Nullable
@@ -143,11 +173,6 @@ public class ItemFluidPacket extends FCBaseItem {
return stack;
}
@Nullable
public static IAEItemStack newAeStack(@Nullable FluidStack fluid) {
return AEItemStack.create(newStack(fluid));
}
@Override
public int getSpriteNumber() {
return 0;
@@ -1,5 +1,8 @@
package com.glodblock.github.common.parts;
import static appeng.util.Platform.convertStack;
import static appeng.util.Platform.stackConvert;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
@@ -11,11 +14,11 @@ import com.glodblock.github.client.textures.FCPartsTexture;
import com.glodblock.github.common.item.ItemFluidDrop;
import com.glodblock.github.common.item.ItemFluidPacket;
import com.glodblock.github.common.parts.base.FCSharedFluidBus;
import com.glodblock.github.inventory.FluidConvertingInventoryAdaptor;
import com.google.common.collect.ImmutableSet;
import appeng.api.config.Actionable;
import appeng.api.config.FuzzyMode;
import appeng.api.config.InsertionMode;
import appeng.api.config.PowerMultiplier;
import appeng.api.config.RedstoneMode;
import appeng.api.config.SchedulingMode;
@@ -43,7 +46,6 @@ import appeng.me.GridAccessException;
import appeng.util.InventoryAdaptor;
import appeng.util.Platform;
import appeng.util.item.AEFluidStack;
import appeng.util.item.AEItemStack;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@@ -269,7 +271,7 @@ public class PartFluidExportBus extends FCSharedFluidBus implements ICraftingReq
}
protected InventoryAdaptor getHandler(TileEntity target) {
return target != null ? FluidConvertingInventoryAdaptor.wrap(target, this.getSide().getOpposite()) : null;
return target != null ? InventoryAdaptor.getAdaptor(target, getSide().getOpposite()) : null;
}
@Override
@@ -282,17 +284,15 @@ public class PartFluidExportBus extends FCSharedFluidBus implements ICraftingReq
final double power = Math.ceil(items.getStackSize() / 1000D);
if (energy.extractAEPower(power, mode, PowerMultiplier.CONFIG) > power - 0.01) {
ItemStack inputStack = items.getItemStack();
ItemStack remaining;
IAEItemStack remaining;
if (mode == Actionable.SIMULATE) {
remaining = d.simulateAdd(inputStack);
remaining = stackConvert(d.simulateAddStack(convertStack(items), InsertionMode.DEFAULT));
} else {
remaining = d.addItems(inputStack);
remaining = stackConvert(d.addStack(convertStack(items), InsertionMode.DEFAULT));
}
return AEItemStack.create(remaining);
return remaining;
}
}
} catch (final GridAccessException e) {
@@ -53,6 +53,7 @@ import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IStorageMonitorable;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.api.util.IConfigManager;
import appeng.helpers.DualityInterface;
import appeng.helpers.IInterfaceHost;
@@ -173,10 +174,13 @@ public class PartFluidP2PInterface extends PartP2PTunnelStatic<PartFluidP2PInter
for (PartFluidP2PInterface p2p : getOutputs()) p2p.duality.addDrops(drops);
} catch (GridAccessException ignored) {}
} else {
if (this.getWaitingToSend() != null) {
for (final ItemStack is : this.getWaitingToSend()) {
if (is != null) {
drops.add(is);
List<IAEStack<?>> waitingList = this.getWaitingToSend();
if (waitingList != null) {
for (final IAEStack<?> as : waitingList) {
if (as instanceof IAEItemStack ais) {
drops.add(ais.getItemStack());
} else if (as instanceof IAEFluidStack afs) {
drops.add(ItemFluidPacket.newStack(afs));
}
}
}
@@ -1,5 +1,6 @@
package com.glodblock.github.common.tile;
import static appeng.util.Platform.writeStackNBT;
import static com.glodblock.github.loader.RecipeLoader.BUCKET;
import javax.annotation.Nonnull;
@@ -17,7 +18,8 @@ import net.minecraftforge.fluids.FluidStack;
import org.apache.commons.lang3.tuple.MutablePair;
import com.glodblock.github.common.item.ItemFluidDrop;
import com.glodblock.github.FluidCraft;
import com.glodblock.github.util.NameConst;
import com.glodblock.github.util.Util;
import appeng.api.AEApi;
@@ -53,6 +55,8 @@ import appeng.tile.events.TileEventType;
import appeng.tile.grid.AENetworkInvTile;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.tile.inventory.InvOperation;
import appeng.util.item.AEItemStack;
import cpw.mods.fml.common.registry.GameRegistry;
public class TileFluidAutoFiller extends AENetworkInvTile
implements ICraftingProvider, IMEMonitorHandlerReceiver<IAEFluidStack>, IGridTickable {
@@ -60,7 +64,7 @@ public class TileFluidAutoFiller extends AENetworkInvTile
private final AppEngInternalInventory inventory = new AppEngInternalInventory(this, 1);
private final BaseActionSource source = new MachineSource(this);
private IItemList<IAEFluidStack> fluids = AEApi.instance().storage().createFluidList();
private final Item encodedPattern = AEApi.instance().definitions().items().encodedPattern().maybeItem().orNull();
private final Item encodedPattern = GameRegistry.findItem(FluidCraft.MODID, NameConst.ITEM_FLUID_ENCODED_PATTERN);
private IAEItemStack returnStack;
private boolean isPowered;
@@ -156,19 +160,21 @@ public class TileFluidAutoFiller extends AENetworkInvTile
MutablePair<Integer, ItemStack> filled = Util.FluidUtil
.fillStack(this.getContainerItem().copy(), new FluidStack(fluid, maxCapacity));
if (filled.right == null) continue;
ItemStack pattern = getPattern(this.getContainerItem(), filled.right);
ItemStack pattern = getPattern(
this.getContainerItem(),
filled.right,
fluidStack.copy().setStackSize(maxCapacity));
ICraftingPatternItem patter = (ICraftingPatternItem) pattern.getItem();
craftingTracker.addCraftingOption(this, patter.getPatternForItem(pattern, getWorldObj()));
}
}
private ItemStack getPattern(ItemStack emptyContainer, ItemStack filledContainer) {
private ItemStack getPattern(ItemStack emptyContainer, ItemStack filledContainer, IAEFluidStack ifs) {
NBTTagList in = new NBTTagList();
NBTTagList out = new NBTTagList();
in.appendTag(emptyContainer.writeToNBT(new NBTTagCompound()));
ItemStack fluidDrop = ItemFluidDrop.newStack(Util.FluidUtil.getFluidFromContainer(filledContainer));
in.appendTag(createItemTag(fluidDrop));
out.appendTag(filledContainer.writeToNBT(new NBTTagCompound()));
in.appendTag(writeStackNBT(AEItemStack.create(emptyContainer), new NBTTagCompound()));
in.appendTag(writeStackNBT(ifs, new NBTTagCompound()));
out.appendTag(writeStackNBT(AEItemStack.create(filledContainer), new NBTTagCompound()));
NBTTagCompound itemTag = new NBTTagCompound();
itemTag.setTag("in", in);
itemTag.setTag("out", out);
@@ -188,8 +194,7 @@ public class TileFluidAutoFiller extends AENetworkInvTile
@Override
public boolean pushPattern(ICraftingPatternDetails patternDetails, InventoryCrafting table) {
this.returnStack = AEApi.instance().storage()
.createItemStack(patternDetails.getCondensedOutputs()[0].getItemStack());
this.returnStack = (IAEItemStack) patternDetails.getCondensedOutputs()[0];
try {
this.getProxy().getTick().alertDevice(this.getProxy().getNode());
} catch (GridAccessException ignored) {
@@ -224,7 +224,6 @@ public class TileFluidInterface extends TileInterface implements IDualHost {
@Override
public void getDrops(World w, int x, int y, int z, List<ItemStack> drops) {
this.fluidDuality.addDrops(drops);
this.fluidDuality.convertDrops(drops, this.getInterfaceDuality().getWaitingToSend());
super.getDrops(w, x, y, z, drops);
}
}
@@ -8,10 +8,6 @@ import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import com.glodblock.github.coremod.transform.CraftingCpuTransformer;
import com.glodblock.github.coremod.transform.CraftingGridCacheTransformer;
import com.glodblock.github.coremod.transform.CraftingTreeNodeTransformer;
import com.glodblock.github.coremod.transform.DualityInterfaceTransformer;
import com.glodblock.github.coremod.transform.ExternalStorageRegistryTransformer;
import com.glodblock.github.coremod.transform.GuiCraftingTransformer;
import com.glodblock.github.coremod.transform.NEITransformer;
@@ -25,10 +21,6 @@ public class FCClassTransformer implements IClassTransformer {
public byte[] transform(String name, String transformedName, byte[] basicClass) {
ClassMapper tform;
switch (transformedName) {
case "appeng.crafting.CraftingTreeNode" -> tform = CraftingTreeNodeTransformer.INSTANCE;
case "appeng.me.cache.CraftingGridCache" -> tform = CraftingGridCacheTransformer.INSTANCE;
case "appeng.me.cluster.implementations.CraftingCPUCluster" -> tform = CraftingCpuTransformer.INSTANCE;
case "appeng.helpers.DualityInterface" -> tform = DualityInterfaceTransformer.INSTANCE;
case "appeng.client.gui.implementations.GuiCraftingCPU", "appeng.client.gui.implementations.GuiCraftConfirm", "net.p455w0rd.wirelesscraftingterminal.client.gui.GuiCraftConfirm", "appeng.client.gui.widgets.GuiCraftingTree" -> tform = GuiCraftingTransformer.INSTANCE;
case "appeng.integration.modules.NEI" -> tform = NEITransformer.INSTANCE;
case "appeng.core.features.registries.ExternalStorageRegistry" -> tform = ExternalStorageRegistryTransformer.INSTANCE;
@@ -1,87 +1,18 @@
package com.glodblock.github.coremod.hooker;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.FluidStack;
import com.glodblock.github.client.gui.GuiFluidCraftConfirm;
import com.glodblock.github.common.item.ItemFluidDrop;
import com.glodblock.github.common.item.ItemFluidPacket;
import com.glodblock.github.inventory.CraftingGridCacheFluidInventoryProxyCell;
import com.glodblock.github.inventory.FluidConvertingInventoryAdaptor;
import com.glodblock.github.inventory.FluidConvertingInventoryCrafting;
import com.glodblock.github.loader.ItemAndBlockHolder;
import com.glodblock.github.util.Ae2Reflect;
import appeng.api.config.Actionable;
import appeng.api.networking.IGrid;
import appeng.api.networking.security.MachineSource;
import appeng.api.networking.storage.IStorageGrid;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.IMEInventoryHandler;
import appeng.api.storage.StorageChannel;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IAEItemStack;
import appeng.client.gui.IGuiTooltipHandler;
import appeng.crafting.MECraftingInventory;
import appeng.me.cache.CraftingGridCache;
import appeng.me.cluster.implementations.CraftingCPUCluster;
import appeng.util.InventoryAdaptor;
public class CoreModHooks {
public static InventoryCrafting wrapCraftingBuffer(InventoryCrafting inv) {
return new FluidConvertingInventoryCrafting(
inv.eventHandler,
inv.inventoryWidth,
inv.getSizeInventory() / inv.inventoryWidth);
}
public static IAEItemStack wrapFluidPacketStack(IAEItemStack stack) {
if (stack.getItem() == ItemAndBlockHolder.PACKET) {
IAEItemStack dropStack = ItemFluidDrop.newAeStack(ItemFluidPacket.getFluidStack(stack.getItemStack()));
if (dropStack != null) {
return dropStack;
}
}
return stack;
}
public static ItemStack removeFluidPackets(InventoryCrafting inv, int index) {
ItemStack stack = inv.getStackInSlot(index);
if (stack != null && stack.getItem() instanceof ItemFluidPacket) {
FluidStack fluid = ItemFluidPacket.getFluidStack(stack);
return ItemFluidDrop.newStack(fluid);
} else {
return stack;
}
}
@Nullable
public static InventoryAdaptor wrapInventory(@Nullable TileEntity tile, ForgeDirection face) {
return tile != null ? FluidConvertingInventoryAdaptor.wrap(tile, face) : null;
}
public static long getCraftingByteCost(IAEItemStack stack) {
return stack.getItem() instanceof ItemFluidDrop ? (long) Math.ceil(stack.getStackSize() / 1000D)
: stack.getStackSize();
}
public static long getFluidDropsByteCost(long totalBytes, long originByte, IAEItemStack stack) {
if (stack != null && stack.getItem() instanceof ItemFluidDrop) {
return (long) Math.ceil(originByte / 1000D) + totalBytes;
}
return originByte + totalBytes;
}
public static ItemStack displayFluid(IAEItemStack aeStack) {
if (aeStack.getItemStack() != null && aeStack.getItemStack().getItem() instanceof ItemFluidDrop) {
FluidStack fluid = ItemFluidDrop.getFluidStack(aeStack.getItemStack());
@@ -89,61 +20,6 @@ public class CoreModHooks {
} else return aeStack.getItemStack();
}
public static long getFluidSize(IAEItemStack aeStack) {
if (aeStack.getItemStack() != null && aeStack.getItemStack().getItem() instanceof ItemFluidDrop) {
return (long) Math.max(aeStack.getStackSize() / 1000D, 1);
} else return aeStack.getStackSize();
}
public static List<IMEInventoryHandler<?>> craftingGridCacheGetCellArray(final CraftingGridCache instance,
final StorageChannel channel) {
// Equivalent to original function, but using the proxy for fluid channel
return channel == StorageChannel.ITEMS ? Arrays.asList(instance)
: Arrays.asList(new CraftingGridCacheFluidInventoryProxyCell(instance));
}
public static void storeFluidItem(CraftingCPUCluster instance) {
final IGrid g = instance.getGrid();
if (g == null) {
return;
}
final IStorageGrid sg = g.getCache(IStorageGrid.class);
final IMEInventory<IAEItemStack> ii = sg.getItemInventory();
final IMEInventory<IAEFluidStack> jj = sg.getFluidInventory();
final MECraftingInventory inventory = (MECraftingInventory) instance.getInventory();
for (IAEItemStack is : inventory.getItemList()) {
is = inventory.extractItems(is.copy(), Actionable.MODULATE, instance.getActionSource());
if (is != null) {
Ae2Reflect.postCPUChange(instance, is, (MachineSource) instance.getActionSource());
if (is.getItem() instanceof ItemFluidDrop) {
IAEFluidStack fluidDrop = ItemFluidDrop.getAeFluidStack(is);
fluidDrop = jj.injectItems(fluidDrop, Actionable.MODULATE, instance.getActionSource());
if (fluidDrop == null) {
is = null;
} else {
is.setStackSize(fluidDrop.getStackSize());
}
} else {
is = ii.injectItems(is, Actionable.MODULATE, instance.getActionSource());
}
}
if (is != null) {
inventory.injectItems(is, Actionable.MODULATE, instance.getActionSource());
}
}
if (inventory.getItemList().isEmpty()) {
Ae2Reflect.setCPUInventory(instance, new MECraftingInventory());
}
instance.markDirty();;
}
public static ItemStack getStackUnderMouse(GuiContainer gui, int mousex, int mousey) {
if (gui instanceof IGuiTooltipHandler guiTooltipHandler) {
return guiTooltipHandler.getHoveredStack();
@@ -1,142 +0,0 @@
package com.glodblock.github.coremod.transform;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import com.glodblock.github.coremod.FCClassTransformer;
public class CraftingCpuTransformer extends FCClassTransformer.ClassMapper {
public static final CraftingCpuTransformer INSTANCE = new CraftingCpuTransformer();
private CraftingCpuTransformer() {
// NO-OP
}
@Override
protected ClassVisitor getClassMapper(ClassVisitor downstream) {
return new TransformCraftingCPUCluster(Opcodes.ASM5, downstream);
}
private static class TransformCraftingCPUCluster extends ClassVisitor {
TransformCraftingCPUCluster(int api, ClassVisitor cv) {
super(api, cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (name.equals("executeCrafting")) {
return new TransformExecuteCrafting(api, super.visitMethod(access, name, desc, signature, exceptions));
} else if (name.equals("cancel")) {
return new TransformStoreItems(api, super.visitMethod(access, name, desc, signature, exceptions));
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
}
private static class TransformExecuteCrafting extends MethodVisitor {
private boolean gotInventory = false;
private int reach_stack = 0;
TransformExecuteCrafting(int api, MethodVisitor mv) {
super(api, mv);
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
if (opcode == Opcodes.GETFIELD && owner.equals("appeng/me/cluster/implementations/CraftingCPUCluster")
&& name.equals("inventory")) {
gotInventory = true;
}
super.visitFieldInsn(opcode, owner, name, desc);
}
@Override
public void visitLineNumber(int line, Label start) {
gotInventory = false;
super.visitLineNumber(line, start);
}
@Override
public void visitJumpInsn(int opcode, Label label) {
if (opcode == Opcodes.IFNULL && reach_stack == 0) {
reach_stack = 1;
}
super.visitJumpInsn(opcode, label);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if (reach_stack == 1) {
if (opcode == Opcodes.INVOKEINTERFACE && owner.equals("appeng/api/storage/data/IAEItemStack")
&& name.equals("getStackSize")) {
reach_stack = 2;
super.visitMethodInsn(
Opcodes.INVOKESTATIC,
"com/glodblock/github/coremod/hooker/CoreModHooks",
"getFluidSize",
"(Lappeng/api/storage/data/IAEItemStack;)J",
false);
return;
}
}
if (opcode == Opcodes.INVOKEVIRTUAL && owner.equals("net/minecraft/inventory/InventoryCrafting")
&& (name.equals("getStackInSlot") || name.equals("func_70301_a"))) {
super.visitMethodInsn(
Opcodes.INVOKESTATIC,
"com/glodblock/github/coremod/hooker/CoreModHooks",
"removeFluidPackets",
"(Lnet/minecraft/inventory/InventoryCrafting;I)Lnet/minecraft/item/ItemStack;",
false);
return;
}
super.visitMethodInsn(opcode, owner, name, desc, itf);
if (gotInventory) {
if (opcode == Opcodes.INVOKESTATIC && owner.equals("appeng/util/item/AEItemStack")
&& name.equals("create")) {
gotInventory = false;
super.visitMethodInsn(
Opcodes.INVOKESTATIC,
"com/glodblock/github/coremod/hooker/CoreModHooks",
"wrapFluidPacketStack",
"(Lappeng/api/storage/data/IAEItemStack;)Lappeng/api/storage/data/IAEItemStack;",
false);
}
} else if (opcode == Opcodes.INVOKESPECIAL && owner.equals("net/minecraft/inventory/InventoryCrafting")
&& name.equals("<init>")) {
super.visitMethodInsn(
Opcodes.INVOKESTATIC,
"com/glodblock/github/coremod/hooker/CoreModHooks",
"wrapCraftingBuffer",
"(Lnet/minecraft/inventory/InventoryCrafting;)Lnet/minecraft/inventory/InventoryCrafting;",
false);
}
}
}
private static class TransformStoreItems extends MethodVisitor {
TransformStoreItems(int api, MethodVisitor mv) {
super(api, mv);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if (opcode == Opcodes.INVOKESPECIAL && owner.equals("appeng/me/cluster/implementations/CraftingCPUCluster")
&& name.equals("storeItems")) {
super.visitMethodInsn(
Opcodes.INVOKESTATIC,
"com/glodblock/github/coremod/hooker/CoreModHooks",
"storeFluidItem",
"(Lappeng/me/cluster/implementations/CraftingCPUCluster;)V",
false);
} else {
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
}
}
}
@@ -1,67 +0,0 @@
package com.glodblock.github.coremod.transform;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import com.glodblock.github.coremod.FCClassTransformer;
public class CraftingGridCacheTransformer extends FCClassTransformer.ClassMapper {
public static final CraftingGridCacheTransformer INSTANCE = new CraftingGridCacheTransformer();
private CraftingGridCacheTransformer() {
// NO-OP
}
@Override
protected ClassVisitor getClassMapper(ClassVisitor downstream) {
return new CraftingGridCacheTransformer.TransformCraftingGridCache(Opcodes.ASM5, downstream);
}
private static class TransformCraftingGridCache extends ClassVisitor {
TransformCraftingGridCache(int api, ClassVisitor cv) {
super(api, cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (name.equals("getCellArray")) {
return new CraftingGridCacheTransformer.ReplaceGetCellArray(
api,
super.visitMethod(access, name, desc, signature, exceptions));
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
}
private static class ReplaceGetCellArray extends MethodVisitor {
private final MethodVisitor target;
ReplaceGetCellArray(int api, MethodVisitor mv) {
// Original method is replaced
super(api, null);
target = mv;
}
@Override
public void visitCode() {
target.visitCode();
// Equivalent to
// return CoreModHooks::craftingGridCacheGetCellArray(this, channel);
target.visitVarInsn(Opcodes.ALOAD, 0);
target.visitVarInsn(Opcodes.ALOAD, 1);
target.visitMethodInsn(
Opcodes.INVOKESTATIC,
"com/glodblock/github/coremod/hooker/CoreModHooks",
"craftingGridCacheGetCellArray",
"(Lappeng/me/cache/CraftingGridCache;Lappeng/api/storage/StorageChannel;)Ljava/util/List;",
false);
target.visitInsn(Opcodes.ARETURN);
target.visitMaxs(2, 3);
target.visitEnd();
}
}
}
@@ -1,102 +0,0 @@
package com.glodblock.github.coremod.transform;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import com.glodblock.github.coremod.FCClassTransformer;
public class CraftingTreeNodeTransformer extends FCClassTransformer.ClassMapper {
public static final CraftingTreeNodeTransformer INSTANCE = new CraftingTreeNodeTransformer();
private CraftingTreeNodeTransformer() {
// NO-OP
}
@Override
protected ClassVisitor getClassMapper(ClassVisitor downstream) {
return new TransformCraftingTreeNode(Opcodes.ASM5, downstream);
}
private static class TransformCraftingTreeNode extends ClassVisitor {
TransformCraftingTreeNode(int api, ClassVisitor cv) {
super(api, cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (name.equals("request")) {
return new TransformRequest(api, super.visitMethod(access, name, desc, signature, exceptions));
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
}
private static class TransformRequest extends MethodVisitor {
private boolean writingBytes = false;
private int cnt = 0;
TransformRequest(int api, MethodVisitor mv) {
super(api, mv);
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
if (opcode == Opcodes.GETFIELD && owner.equals("appeng/crafting/CraftingTreeNode")
&& name.equals("bytes")) {
writingBytes = true;
}
super.visitFieldInsn(opcode, owner, name, desc);
}
@Override
public void visitLineNumber(int line, Label start) {
writingBytes = false; // no write here
super.visitLineNumber(line, start);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if (writingBytes && opcode == Opcodes.INVOKEINTERFACE
&& owner.equals("appeng/api/storage/data/IAEItemStack")
&& name.equals("getStackSize")) {
writingBytes = false;
cnt++;
super.visitMethodInsn(
Opcodes.INVOKESTATIC,
"com/glodblock/github/coremod/hooker/CoreModHooks",
"getCraftingByteCost",
"(Lappeng/api/storage/data/IAEItemStack;)J",
false);
} else {
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
}
@Override
public void visitInsn(int opcode) {
if (writingBytes && cnt == 5 && opcode == Opcodes.LADD) {
super.visitVarInsn(Opcodes.ALOAD, 0);
super.visitFieldInsn(
Opcodes.GETFIELD,
"appeng/crafting/CraftingTreeNode",
"what",
"Lappeng/api/storage/data/IAEItemStack;");
super.visitMethodInsn(
Opcodes.INVOKESTATIC,
"com/glodblock/github/coremod/hooker/CoreModHooks",
"getFluidDropsByteCost",
"(JJLappeng/api/storage/data/IAEItemStack;)J",
false);
writingBytes = false;
cnt++;
return;
}
super.visitInsn(opcode);
}
}
}
@@ -1,60 +0,0 @@
package com.glodblock.github.coremod.transform;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import com.glodblock.github.coremod.FCClassTransformer;
public class DualityInterfaceTransformer extends FCClassTransformer.ClassMapper {
public static final DualityInterfaceTransformer INSTANCE = new DualityInterfaceTransformer();
private DualityInterfaceTransformer() {
// NO-OP
}
@Override
protected ClassVisitor getClassMapper(ClassVisitor downstream) {
return new TransformDualityInterface(Opcodes.ASM5, downstream);
}
private static class TransformDualityInterface extends ClassVisitor {
TransformDualityInterface(int api, ClassVisitor cv) {
super(api, cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
return switch (name) {
case "pushItemsOut", "pushPattern", "isBusy" -> new TransformInvAdaptorCalls(
api,
super.visitMethod(access, name, desc, signature, exceptions));
default -> super.visitMethod(access, name, desc, signature, exceptions);
};
}
}
private static class TransformInvAdaptorCalls extends MethodVisitor {
private TransformInvAdaptorCalls(int api, MethodVisitor mv) {
super(api, mv);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if (opcode == Opcodes.INVOKESTATIC && owner.equals("appeng/util/InventoryAdaptor")
&& name.equals("getAdaptor")) {
super.visitMethodInsn(
Opcodes.INVOKESTATIC,
"com/glodblock/github/coremod/hooker/CoreModHooks",
"wrapInventory",
"(Lnet/minecraft/tileentity/TileEntity;Lnet/minecraftforge/common/util/ForgeDirection;)Lappeng/util/InventoryAdaptor;",
false);
} else {
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
}
}
}
@@ -1,85 +0,0 @@
package com.glodblock.github.inventory;
import org.jetbrains.annotations.NotNull;
import com.glodblock.github.common.item.ItemFluidDrop;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.storage.IMEInventoryHandler;
import appeng.api.storage.StorageChannel;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
import appeng.me.cache.CraftingGridCache;
public class CraftingGridCacheFluidInventoryProxyCell implements IMEInventoryHandler<IAEFluidStack> {
private final CraftingGridCache inner;
public CraftingGridCacheFluidInventoryProxyCell(final CraftingGridCache craftingGridCache) {
inner = craftingGridCache;
}
@Override
public IAEFluidStack injectItems(IAEFluidStack input, Actionable type, BaseActionSource src) {
return ItemFluidDrop
.getAeFluidStack((IAEItemStack) inner.injectItems(ItemFluidDrop.newAeStack(input), type, src));
}
@Override
public IAEFluidStack extractItems(IAEFluidStack request, Actionable mode, BaseActionSource src) {
return null;
}
@Override
public IItemList<IAEFluidStack> getAvailableItems(IItemList<IAEFluidStack> out, int iteration) {
return out;
}
@Override
public IAEFluidStack getAvailableItem(@NotNull IAEFluidStack request, int iteration) {
return null;
}
@Override
public StorageChannel getChannel() {
return StorageChannel.FLUIDS;
}
@Override
public AccessRestriction getAccess() {
return inner.getAccess();
}
@Override
public boolean isPrioritized(IAEFluidStack input) {
return inner.isPrioritized(input);
}
@Override
public boolean canAccept(IAEFluidStack input) {
return inner.canAccept(ItemFluidDrop.newAeStack(input));
}
@Override
public int getPriority() {
return inner.getPriority();
}
@Override
public int getSlot() {
return inner.getSlot();
}
@Override
public boolean validForPass(int i) {
return inner.validForPass(i);
}
@Override
public boolean isAutoCraftingInventory() {
return inner.isAutoCraftingInventory();
}
}
@@ -1,539 +0,0 @@
package com.glodblock.github.inventory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import javax.annotation.Nullable;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTankInfo;
import net.minecraftforge.fluids.IFluidHandler;
import com.glodblock.github.common.Config;
import com.glodblock.github.common.item.ItemFluidDrop;
import com.glodblock.github.common.item.ItemFluidPacket;
import com.glodblock.github.common.parts.PartFluidExportBus;
import com.glodblock.github.common.parts.PartFluidInterface;
import com.glodblock.github.common.parts.PartFluidP2PInterface;
import com.glodblock.github.common.tile.TileFluidInterface;
import com.glodblock.github.util.BlockPos;
import com.glodblock.github.util.ModAndClassUtil;
import com.glodblock.github.util.Util;
import appeng.api.config.FuzzyMode;
import appeng.api.config.InsertionMode;
import appeng.api.config.Upgrades;
import appeng.api.parts.IPart;
import appeng.helpers.DualityInterface;
import appeng.helpers.IInterfaceHost;
import appeng.me.GridAccessException;
import appeng.me.helpers.AENetworkProxy;
import appeng.parts.p2p.PartP2PLiquids;
import appeng.tile.misc.TileInterface;
import appeng.tile.networking.TileCableBus;
import appeng.util.InventoryAdaptor;
import appeng.util.inv.IInventoryDestination;
import appeng.util.inv.ItemSlot;
import cofh.api.transport.IItemDuct;
import crazypants.enderio.conduit.ConnectionMode;
import crazypants.enderio.conduit.item.IItemConduit;
import crazypants.enderio.conduit.liquid.ILiquidConduit;
import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
import gregtech.api.metatileentity.MetaPipeEntity;
public class FluidConvertingInventoryAdaptor extends InventoryAdaptor {
// facing is the target TE direction
// |T|-facing->|I|
public FluidConvertingInventoryAdaptor(TileEntity te, @Nullable InventoryAdaptor invItems,
@Nullable IFluidHandler invFluids, ForgeDirection facing, BlockPos pos, boolean isOnmi) {
this.invItems = invItems;
this.invFluids = invFluids;
this.side = facing;
this.posInterface = pos;
this.onmi = isOnmi;
this.selfInterface = getInterfaceTE(pos.getTileEntity(), facing.getOpposite());
this.targetInterface = getInterfaceTE(te, facing);
}
private final InventoryAdaptor invItems;
private final IFluidHandler invFluids;
private final ForgeDirection side;
private final BlockPos posInterface;
@Nullable
private final IInterfaceHost targetInterface;
@Nullable
private final IInterfaceHost selfInterface;
private final boolean onmi;
private static Method eioTypeCheck;
private static Class<?> conduitClazz;
static {
if (ModAndClassUtil.EIO) {
try {
conduitClazz = Class.forName("crazypants.enderio.conduit.TileConduitBundle");
eioTypeCheck = conduitClazz.getDeclaredMethod("getConduit", Class.class);
} catch (ClassNotFoundException | NoSuchMethodException e) {
eioTypeCheck = null;
}
} else {
eioTypeCheck = null;
}
}
public static InventoryAdaptor wrap(TileEntity capProvider, ForgeDirection face) {
TileEntity inter = capProvider.getWorldObj().getTileEntity(
capProvider.xCoord + face.offsetX,
capProvider.yCoord + face.offsetY,
capProvider.zCoord + face.offsetZ);
if (!Config.noFluidPacket && !(inter instanceof TileFluidInterface
|| Util.getPart(inter, face.getOpposite()) instanceof PartFluidInterface
|| Util.getPart(inter, face.getOpposite()) instanceof PartFluidExportBus
|| Util.getPart(inter, face.getOpposite()) instanceof PartFluidP2PInterface))
return InventoryAdaptor.getAdaptor(capProvider, face);
if (InventoryAdaptor.getAdaptor(capProvider, face) == null
&& !(ModAndClassUtil.EIO && capProvider instanceof IItemDuct)) {
if (capProvider instanceof IFluidHandler tank) {
if (tank.getTankInfo(face) == null || !(tank.getTankInfo(face).length > 0)) return null;
} else {
return null;
}
}
InventoryAdaptor item = InventoryAdaptor.getAdaptor(capProvider, face);
IFluidHandler fluid = capProvider instanceof IFluidHandler ? (IFluidHandler) capProvider : null;
boolean onmi = false;
if (inter instanceof TileInterface in) {
onmi = in.getTargets().size() > 1;
}
return new FluidConvertingInventoryAdaptor(capProvider, item, fluid, face, new BlockPos(inter), onmi);
}
public ItemStack addItems(ItemStack toBeAdded, InsertionMode insertionMode) {
FluidStack fluid = Util.getFluidFromVirtual(toBeAdded);
if (!this.onmi) {
if (!checkValidSide(
this.posInterface.getOffSet(this.side.getOpposite()).getTileEntity(),
this.side.getOpposite())) {
return toBeAdded;
}
if (fluid != null) {
int filled = fillSideFluid(fluid, this.invFluids, this.side, true);
fluid.amount -= filled;
return ItemFluidDrop.newStack(fluid);
} else {
ItemStack notFilled = fillSideItem(toBeAdded, this.invItems, insertionMode, true);
if (notFilled != null) {
// Fill EIO Conduit at last.
return fillEIOConduit(
notFilled,
this.posInterface.getOffSet(this.side.getOpposite()).getTileEntity(),
this.side);
}
return null;
}
} else {
if (fluid != null) {
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
if (fluid.amount <= 0) {
return null;
}
if (!checkValidSide(this.posInterface.getOffSet(dir).getTileEntity(), dir)) {
continue;
}
int filled = fillSideFluid(fluid, getSideFluid(dir), dir.getOpposite(), true);
fluid.amount -= filled;
}
return ItemFluidPacket.newStack(fluid);
} else {
ItemStack item = toBeAdded.copy();
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
if (item == null || item.stackSize <= 0) {
return null;
}
if (!checkValidSide(this.posInterface.getOffSet(dir).getTileEntity(), dir)) {
continue;
}
item = fillSideItem(item, getSideItem(dir), insertionMode, true);
}
// Fill EIO Conduit at last.
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
if (item == null || item.stackSize <= 0) {
return null;
}
if (!checkValidSide(this.posInterface.getOffSet(dir).getTileEntity(), dir)) {
continue;
}
item = fillEIOConduit(item, this.posInterface.getOffSet(dir).getTileEntity(), dir.getOpposite());
}
return item;
}
}
}
@Override
public ItemStack addItems(ItemStack toBeAdded) {
return addItems(toBeAdded, InsertionMode.DEFAULT);
}
@Override
public ItemStack simulateAdd(ItemStack toBeSimulated) {
return simulateAdd(toBeSimulated, InsertionMode.DEFAULT);
}
@Override
public ItemStack simulateAdd(ItemStack toBeSimulated, InsertionMode insertionMode) {
FluidStack fluid = Util.getFluidFromVirtual(toBeSimulated);
if (!this.onmi) {
if (!checkValidSide(
this.posInterface.getOffSet(this.side.getOpposite()).getTileEntity(),
this.side.getOpposite())) {
return toBeSimulated;
}
if (fluid != null) {
int filled = fillSideFluid(fluid, this.invFluids, this.side, false);
fluid.amount -= filled;
return ItemFluidPacket.newStack(fluid);
} else {
// Assert EIO conduit can hold all item, as it is the origin practice in AE2
if (isConduit(this.posInterface.getOffSet(this.side.getOpposite()).getTileEntity())) {
return null;
} else {
return fillSideItem(toBeSimulated, this.invItems, insertionMode, false);
}
}
} else {
// In onmi mode, fluid/item only need to be partly inserted.
boolean sus = false;
if (fluid != null) {
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
if (!checkValidSide(this.posInterface.getOffSet(dir).getTileEntity(), dir)) {
continue;
}
int filled = fillSideFluid(fluid, getSideFluid(dir), dir.getOpposite(), false);
if (filled > 0) {
sus = true;
break;
}
}
} else {
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
if (!checkValidSide(this.posInterface.getOffSet(dir).getTileEntity(), dir)) {
continue;
}
// Assert EIO conduit can hold all item, as it is the origin practice in AE2
if (isConduit(this.posInterface.getOffSet(dir).getTileEntity())) {
return null;
}
ItemStack notFilled = fillSideItem(toBeSimulated, getSideItem(dir), insertionMode, false);
if (notFilled == null || notFilled.stackSize < toBeSimulated.stackSize) {
sus = true;
break;
}
}
}
return sus ? null : toBeSimulated;
}
}
@Override
public ItemStack removeItems(int amount, ItemStack filter, IInventoryDestination destination) {
return invItems != null ? invItems.removeItems(amount, filter, destination) : null;
}
@Override
public ItemStack simulateRemove(int amount, ItemStack filter, IInventoryDestination destination) {
return invItems != null ? invItems.simulateRemove(amount, filter, destination) : null;
}
@Override
public ItemStack removeSimilarItems(int amount, ItemStack filter, FuzzyMode fuzzyMode,
IInventoryDestination destination) {
return invItems != null ? invItems.removeSimilarItems(amount, filter, fuzzyMode, destination) : null;
}
@Override
public ItemStack simulateSimilarRemove(int amount, ItemStack filter, FuzzyMode fuzzyMode,
IInventoryDestination destination) {
return invItems != null ? invItems.simulateSimilarRemove(amount, filter, fuzzyMode, destination) : null;
}
@Override
public boolean containsItems() {
if (!this.onmi) {
// If there is no fluid tank or item inventory, it shouldn't send stuff here.
return checkItemFluids(this.invFluids, this.invItems, this.side) > 0;
}
boolean anyValid = false;
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
// Avoid sending stuff into itself me network
TileEntity te = this.posInterface.getOffSet(dir).getTileEntity();
if (te != null && checkValidSide(te, dir)) {
if (!isConduit(te) || (!isItemConduit(te) && isFluidConduitConnected(te, dir))) {
final int result = checkItemFluids(
this.getSideFluid(dir),
this.getSideItem(dir),
dir.getOpposite());
if (result == 1) {
return true;
}
if (result != 2) {
anyValid = true;
}
}
}
}
// Same here. if there is no fluid tank or item inventory existed, it shouldn't send stuff here.
return !anyValid;
}
public boolean hasSlots() {
return (invFluids != null && invFluids.getTankInfo(side).length > 0) || (invItems != null);
}
@Override
public Iterator<ItemSlot> iterator() {
FluidTankInfo[] info = null;
if (invFluids != null) {
info = invFluids.getTankInfo(side);
}
// Null check is needed because some tank infos return null (EIO conduits...)
if (info == null) {
info = new FluidTankInfo[0];
}
return new SlotIterator(info, invItems != null ? invItems.iterator() : Collections.emptyIterator());
}
private IFluidHandler getSideFluid(ForgeDirection direction) {
TileEntity te = this.posInterface.getOffSet(direction).getTileEntity();
if (te instanceof IFluidHandler) {
return (IFluidHandler) te;
}
return null;
}
private int fillSideFluid(FluidStack fluid, IFluidHandler tank, ForgeDirection direction, boolean doFill) {
if (tank != null) {
return tank.fill(direction, fluid, doFill);
}
return 0;
}
// EIO conduit isn't considered here
private ItemStack fillSideItem(ItemStack item, InventoryAdaptor inv, InsertionMode mode, boolean doFill) {
if (inv != null) {
if (doFill) {
return inv.addItems(item, mode);
} else {
return inv.simulateAdd(item, mode);
}
}
return item;
}
private int gtMachineCircuitCheck(InventoryAdaptor ad) {
if (ad == null) {
return 0;
}
for (ItemSlot i : ad) {
ItemStack is = i.getItemStack();
if (is == null || Objects.requireNonNull(is.getItem()).getUnlocalizedName().equals("gt.integrated_circuit"))
continue;
return 1;
}
return 0;
}
private boolean isGTMachine(Object o) {
if (!(ModAndClassUtil.GT5 || ModAndClassUtil.GT5NH)) return false;
if (o instanceof TileEntity te) {
return te.getBlockType().getUnlocalizedName().equals("gt.blockmachines");
}
return false;
}
private boolean isFluidConduitConnected(TileEntity te, ForgeDirection dir) {
try {
ILiquidConduit liquidConduit = (ILiquidConduit) eioTypeCheck.invoke(te, ILiquidConduit.class);
return liquidConduit != null
&& liquidConduit.getConnectionMode(dir.getOpposite()) != ConnectionMode.DISABLED;
} catch (IllegalAccessException | InvocationTargetException e) {
return false;
}
}
private boolean isItemConduit(TileEntity te) {
if (isConduit(te)) {
try {
return eioTypeCheck.invoke(te, IItemConduit.class) != null;
} catch (InvocationTargetException | IllegalAccessException e) {
return false;
}
}
return false;
}
private boolean isConduit(TileEntity te) {
return ModAndClassUtil.EIO && conduitClazz.isInstance(te);
}
private ItemStack fillEIOConduit(ItemStack item, TileEntity te, ForgeDirection direction) {
if (isConduit(te)) {
return ((IItemDuct) te).insertItem(direction, item);
}
return item;
}
private InventoryAdaptor getSideItem(ForgeDirection direction) {
TileEntity te = this.posInterface.getOffSet(direction).getTileEntity();
return InventoryAdaptor.getAdaptor(te, direction.getOpposite());
}
// 0 - It is empty
// 1 - It contains item/fluid
// 2 - It doesn't exist
private int checkItemFluids(IFluidHandler tank, InventoryAdaptor inv, ForgeDirection direction) {
if (tank == null && inv == null) {
return 2;
}
if (targetInterface != null && targetInterface.getInstalledUpgrades(Upgrades.ADVANCED_BLOCKING) > 0
&& targetInterface instanceof IDualHost
&& !((IDualHost) targetInterface).getDualityFluid().getFluidInventory().getStorageList().isEmpty()) {
return 1;
}
if (tank != null && tank.getTankInfo(direction) != null) {
List<FluidTankInfo[]> tankInfos = new LinkedList<>();
if (Util.getPart(tank, direction) instanceof PartP2PLiquids invFluidsP2P) {
// read other ends of p2p for blocking mode
try {
Iterator<PartP2PLiquids> it = invFluidsP2P.getOutputs().iterator();
boolean checkedInput = false;
while (it.hasNext() || !checkedInput) {
PartP2PLiquids p2p;
if (it.hasNext()) {
p2p = it.next();
} else {
p2p = invFluidsP2P.getInput();
checkedInput = true;
}
if (p2p == invFluidsP2P || p2p == null) continue;
IFluidHandler target = p2p.getTarget();
if (target == null) continue;
FluidTankInfo[] info = target.getTankInfo(p2p.getSide().getOpposite());
if (info != null) {
tankInfos.add(info);
}
}
} catch (GridAccessException ignore) {}
} else {
tankInfos.add(tank.getTankInfo(direction));
}
boolean hasTank = false;
for (FluidTankInfo[] tankInfoArray : tankInfos) {
for (FluidTankInfo tankInfo : tankInfoArray) {
hasTank = true;
FluidStack fluid = tankInfo.fluid;
if (fluid != null && fluid.amount > 0) {
return 1;
}
}
}
if (!hasTank && inv == null) {
return 2;
}
}
if (isGTMachine(tank)) {
return gtMachineCircuitCheck(inv);
}
return inv != null && inv.containsItems() ? 1 : 0;
}
private boolean checkValidSide(TileEntity te, ForgeDirection direction) {
if (isGTMachine(te)) {
return checkGTPipeConnection(te, direction.getOpposite());
}
return isDifferentGrid(getInterfaceTE(te, direction.getOpposite()));
}
private boolean checkGTPipeConnection(TileEntity te, ForgeDirection direction) {
if (te instanceof IGregTechTileEntity) {
IMetaTileEntity mte = ((IGregTechTileEntity) te).getMetaTileEntity();
if (mte instanceof MetaPipeEntity) {
return ((MetaPipeEntity) mte).isConnectedAtSide(direction);
}
}
return true;
}
private static IInterfaceHost getInterfaceTE(TileEntity te, ForgeDirection face) {
if (te instanceof IInterfaceHost) {
return (IInterfaceHost) te;
} else if (te instanceof TileCableBus) {
IPart part = ((TileCableBus) te).getPart(face);
if (part instanceof IInterfaceHost) {
return (IInterfaceHost) part;
}
}
return null;
}
private boolean isDifferentGrid(IInterfaceHost target) {
if (this.selfInterface != null && target != null) {
DualityInterface other = target.getInterfaceDuality();
DualityInterface self = this.selfInterface.getInterfaceDuality();
try {
AENetworkProxy proxy1 = other.getProxy();
AENetworkProxy proxy2 = self.getProxy();
if (proxy1.getGrid() == proxy2.getGrid()) {
return false;
}
} catch (GridAccessException e) {
return true;
}
}
return true;
}
private static class SlotIterator implements Iterator<ItemSlot> {
private final FluidTankInfo[] tanks;
private final Iterator<ItemSlot> itemSlots;
private int nextSlotIndex = 0;
SlotIterator(FluidTankInfo[] tanks, Iterator<ItemSlot> itemSlots) {
this.tanks = tanks;
this.itemSlots = itemSlots;
}
@Override
public boolean hasNext() {
return itemSlots.hasNext() || nextSlotIndex < tanks.length;
}
@Override
public ItemSlot next() {
if (nextSlotIndex < tanks.length) {
FluidStack fluid = tanks[nextSlotIndex].fluid;
ItemSlot slot = new ItemSlot();
slot.setSlot(nextSlotIndex++);
slot.setItemStack(fluid != null ? ItemFluidPacket.newStack(fluid) : null);
slot.setExtractable(false);
return slot;
} else {
ItemSlot slot = itemSlots.next();
slot.setSlot(nextSlotIndex++);
return slot;
}
}
}
}
@@ -1,33 +0,0 @@
package com.glodblock.github.inventory;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import com.glodblock.github.common.item.ItemFluidDrop;
import com.glodblock.github.common.item.ItemFluidPacket;
public class FluidConvertingInventoryCrafting extends InventoryCrafting {
public FluidConvertingInventoryCrafting(Container container, int width, int height) {
super(container, width, height);
}
@Override
public void setInventorySlotContents(int index, ItemStack stack) {
if (stack != null && stack.getItem() instanceof ItemFluidDrop) {
FluidStack fluid = ItemFluidDrop.getFluidStack(stack);
if (fluid != null) {
super.setInventorySlotContents(index, ItemFluidPacket.newStack(new FluidStack(fluid, stack.stackSize)));
} else {
super.setInventorySlotContents(
index,
ItemFluidPacket.newStack(new FluidStack(FluidRegistry.WATER, 1000)));
}
} else {
super.setInventorySlotContents(index, stack);
}
}
}
@@ -8,16 +8,11 @@ import net.minecraftforge.fluids.IFluidHandler;
import appeng.api.implementations.IUpgradeableHost;
import appeng.api.networking.IGrid;
import appeng.api.networking.crafting.ICraftingCPU;
import appeng.api.networking.crafting.ICraftingJob;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.networking.security.MachineSource;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.data.IAEItemStack;
import appeng.container.implementations.ContainerCraftConfirm;
import appeng.container.implementations.ContainerUpgradeable;
import appeng.container.implementations.CraftingCPURecord;
import appeng.crafting.MECraftingInventory;
import appeng.helpers.DualityInterface;
import appeng.me.cluster.implementations.CraftingCPUCluster;
import appeng.me.helpers.AENetworkProxy;
@@ -32,19 +27,12 @@ public class Ae2Reflect {
private static final Field fInventory_containerUpgrade;
private static final Field fAEPass_internal;
private static final Field fAEInv_partitionList;
private static final Field fCPU_cpu;
private static final Field fCPU_myName;
private static final Field fCPU_processors;
private static final Field fCPU_size;
private static final Field fCPU_inventory;
private static final Field fCPU_machineSrc;
private static final Field fContainerUpgradeable_upgradeable;
private static final Field fDualInterface_gridProxy;
private static final Field fCraftConfirm_result;
private static final Method mItemSlot_setExtractable;
private static final Method mCPU_getGrid;
private static final Method mCPU_postChange;
private static final Method mCPU_markDirty;
private static final Method mP2PLiquids_getTarget;
private static final Method mCraftConfirm_getGrid;
@@ -53,22 +41,11 @@ public class Ae2Reflect {
fInventory_containerUpgrade = reflectField(ContainerUpgradeable.class, "upgradeable");
fAEPass_internal = reflectField(MEPassThrough.class, "internal");
fAEInv_partitionList = reflectField(MEInventoryHandler.class, "myPartitionList");
fCPU_cpu = Ae2Reflect.reflectField(CraftingCPURecord.class, "cpu");
fCPU_myName = Ae2Reflect.reflectField(CraftingCPURecord.class, "myName");
fCPU_processors = Ae2Reflect.reflectField(CraftingCPURecord.class, "processors");
fCPU_size = Ae2Reflect.reflectField(CraftingCPURecord.class, "size");
fCPU_inventory = Ae2Reflect.reflectField(CraftingCPUCluster.class, "inventory");
fCPU_machineSrc = Ae2Reflect.reflectField(CraftingCPUCluster.class, "machineSrc");
fContainerUpgradeable_upgradeable = Ae2Reflect.reflectField(ContainerUpgradeable.class, "upgradeable");
mItemSlot_setExtractable = reflectMethod(ItemSlot.class, "setExtractable", boolean.class);
fDualInterface_gridProxy = reflectField(DualityInterface.class, "gridProxy");
mCPU_getGrid = reflectMethod(CraftingCPUCluster.class, "getGrid");
mCPU_postChange = reflectMethod(
CraftingCPUCluster.class,
"postChange",
IAEItemStack.class,
BaseActionSource.class);
mCPU_markDirty = reflectMethod(CraftingCPUCluster.class, "markDirty");
mP2PLiquids_getTarget = reflectMethod(PartP2PLiquids.class, "getTarget");
fCraftConfirm_result = reflectField(ContainerCraftConfirm.class, "result");
mCraftConfirm_getGrid = reflectMethod(ContainerCraftConfirm.class, "getGrid");
@@ -135,26 +112,11 @@ public class Ae2Reflect {
}
}
@Deprecated
public static ICraftingCPU getCPU(CraftingCPURecord cpu) {
return Ae2Reflect.readField(cpu, fCPU_cpu);
}
@Deprecated
public static String getName(CraftingCPURecord cpu) {
return Ae2Reflect.readField(cpu, fCPU_myName);
}
@Deprecated
public static int getProcessors(CraftingCPURecord cpu) {
return Ae2Reflect.readField(cpu, fCPU_processors);
}
@Deprecated
public static long getSize(CraftingCPURecord cpu) {
return Ae2Reflect.readField(cpu, fCPU_size);
}
@Deprecated
public static IUpgradeableHost getUpgradeList(ContainerUpgradeable container) {
return Ae2Reflect.readField(container, fInventory_containerUpgrade);
@@ -183,20 +145,6 @@ public class Ae2Reflect {
return Ae2Reflect.readField(ccc, fCraftConfirm_result);
}
@Deprecated
public static MECraftingInventory getCPUInventory(CraftingCPUCluster cpu) {
return Ae2Reflect.readField(cpu, fCPU_inventory);
}
public static void setCPUInventory(CraftingCPUCluster cpu, MECraftingInventory value) {
Ae2Reflect.writeField(cpu, fCPU_inventory, value);
}
@Deprecated
public static MachineSource getCPUSource(CraftingCPUCluster cpu) {
return Ae2Reflect.readField(cpu, fCPU_machineSrc);
}
@Deprecated
public static IUpgradeableHost getUpgradeableHost(ContainerUpgradeable owner) {
return Ae2Reflect.readField(owner, fContainerUpgradeable_upgradeable);
@@ -207,23 +155,6 @@ public class Ae2Reflect {
return Ae2Reflect.readField(owner, fDualInterface_gridProxy);
}
public static void postCPUChange(CraftingCPUCluster cpu, IAEItemStack stack, MachineSource src) {
try {
mCPU_postChange.invoke(cpu, stack, src);
} catch (Exception e) {
throw new IllegalStateException("Failed to invoke method: " + mCPU_postChange, e);
}
}
@Deprecated
public static void markCPUDirty(CraftingCPUCluster cpu) {
try {
mCPU_markDirty.invoke(cpu);
} catch (Exception e) {
throw new IllegalStateException("Failed to invoke method: " + mCPU_markDirty, e);
}
}
@Deprecated
public static IFluidHandler getP2PLiquidTarget(PartP2PLiquids p2p) {
try {
@@ -1,5 +1,8 @@
package com.glodblock.github.util;
import static appeng.util.Platform.readStackNBT;
import static appeng.util.Platform.stackConvert;
import java.util.Arrays;
import java.util.Objects;
@@ -14,7 +17,9 @@ import net.minecraftforge.common.util.Constants;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.helpers.PatternHelper;
import appeng.util.Platform;
import appeng.util.item.AEItemStack;
public class FluidPatternDetails implements ICraftingPatternDetails, Comparable<FluidPatternDetails> {
@@ -22,6 +27,7 @@ public class FluidPatternDetails implements ICraftingPatternDetails, Comparable<
private final ItemStack patternStack;
private IAEItemStack patternStackAe;
private IAEItemStack[] inputs = null, inputsCond = null, outputs = null, outputsCond = null;
private IAEStack<?>[] aeInputs = null, aeInputsCond = null, aeOutputs = null, aeOutputsCond = null;
private int priority = 0;
private int combine = 0;
private int beSubstitute = 0;
@@ -83,18 +89,42 @@ public class FluidPatternDetails implements ICraftingPatternDetails, Comparable<
return checkInitialized(inputs);
}
@Override
public IAEStack<?>[] getAEInputs() {
return checkInitialized(aeInputs);
}
@Override
public IAEItemStack[] getCondensedInputs() {
return checkInitialized(inputsCond);
}
public boolean setInputs(IAEItemStack[] inputs) {
IAEItemStack[] condensed = condenseStacks(inputs);
@Override
public IAEStack<?>[] getCondensedAEInputs() {
return checkInitialized(aeInputsCond);
}
public boolean setInputs(IAEStack<?>[] inputs) {
IAEStack<?>[] condensed = condenseAEStacks(inputs);
if (condensed.length == 0) {
return false;
}
this.inputs = inputs;
this.inputsCond = condensed;
this.aeInputs = inputs;
this.aeInputsCond = condensed;
IAEItemStack[] legacy = new IAEItemStack[inputs.length];
for (int i = 0; i < inputs.length; i++) {
if (inputs[i] != null) {
if (inputs[i].isItem()) {
legacy[i] = (IAEItemStack) inputs[i];
} else {
legacy[i] = stackConvert(inputs[i]);
}
}
}
this.inputs = legacy;
this.inputsCond = condenseStacks(legacy);
return true;
}
@@ -103,18 +133,42 @@ public class FluidPatternDetails implements ICraftingPatternDetails, Comparable<
return checkInitialized(outputs);
}
@Override
public IAEStack<?>[] getAEOutputs() {
return checkInitialized(aeOutputs);
}
@Override
public IAEItemStack[] getCondensedOutputs() {
return checkInitialized(outputsCond);
}
public boolean setOutputs(IAEItemStack[] outputs) {
IAEItemStack[] condensed = condenseStacks(outputs);
@Override
public IAEStack<?>[] getCondensedAEOutputs() {
return checkInitialized(aeOutputsCond);
}
public boolean setOutputs(IAEStack<?>[] outputs) {
IAEStack<?>[] condensed = condenseAEStacks(outputs);
if (condensed.length == 0) {
return false;
}
this.outputs = Arrays.stream(outputs).filter(Objects::nonNull).toArray(IAEItemStack[]::new);
this.outputsCond = condensed;
this.aeOutputs = Arrays.stream(outputs).filter(Objects::nonNull).toArray(IAEStack<?>[]::new);
this.aeOutputsCond = condensed;
IAEItemStack[] legacy = new IAEItemStack[outputs.length];
for (int i = 0; i < outputs.length; i++) {
if (outputs[i] != null) {
if (outputs[i].isItem()) {
legacy[i] = (IAEItemStack) outputs[i];
} else {
legacy[i] = stackConvert(outputs[i]);
}
}
}
this.outputs = legacy;
this.outputsCond = condenseStacks(legacy);
return true;
}
@@ -122,11 +176,20 @@ public class FluidPatternDetails implements ICraftingPatternDetails, Comparable<
return PatternHelper.convertToCondensedList(stacks);
}
private static IAEStack<?>[] condenseAEStacks(IAEStack<?>[] stacks) {
return PatternHelper.convertToCondensedAEList(stacks);
}
@Override
public ItemStack getOutput(InventoryCrafting craftingInv, World world) {
throw new IllegalStateException("Not a crafting recipe!");
}
@Override
public boolean isValidItemForSlot(int slotIndex, IAEStack<?> stack, World world) {
throw new IllegalStateException("Not a crafting recipe!");
}
@Override
public boolean isValidItemForSlot(int slotIndex, ItemStack itemStack, World world) {
throw new IllegalStateException("Not a crafting recipe!");
@@ -171,12 +234,12 @@ public class FluidPatternDetails implements ICraftingPatternDetails, Comparable<
return patternStack;
}
public static NBTTagList writeStackArray(IAEItemStack[] stacks) {
public static NBTTagList writeStackArray(IAEStack<?>[] stacks) {
NBTTagList listTag = new NBTTagList();
for (IAEItemStack stack : stacks) {
for (IAEStack<?> stack : stacks) {
// see note at top of class
NBTTagCompound stackTag = new NBTTagCompound();
if (stack != null) stack.writeToNBT(stackTag);
Platform.writeStackNBT(stack, stackTag);
listTag.appendTag(stackTag);
}
return listTag;
@@ -196,11 +259,11 @@ public class FluidPatternDetails implements ICraftingPatternDetails, Comparable<
&& setOutputs(readStackArray(tag.getTagList("out", Constants.NBT.TAG_COMPOUND)));
}
public static IAEItemStack[] readStackArray(NBTTagList listTag) {
public static IAEStack<?>[] readStackArray(NBTTagList listTag) {
// see note at top of class
IAEItemStack[] stacks = new IAEItemStack[listTag.tagCount()];
IAEStack<?>[] stacks = new IAEStack<?>[listTag.tagCount()];
for (int i = 0; i < stacks.length; i++) {
stacks[i] = AEItemStack.loadItemStackFromNBT(listTag.getCompoundTagAt(i));
stacks[i] = readStackNBT(listTag.getCompoundTagAt(i), true);
}
return stacks;
}