diff --git a/dependencies.gradle b/dependencies.gradle index 0899277f..c2dd1136 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -2,7 +2,7 @@ dependencies { compile('com.github.GTNewHorizons:NotEnoughItems:2.3.32-GTNH:dev') - compile('com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta-158-GTNH:dev') + compile('com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta-160-GTNH:dev') compile('curse.maven:cofh-core-69162:2388751') compile('com.github.GTNewHorizons:waila:1.5.22:dev') compileOnly('com.github.GTNewHorizons:ExtraCells2:2.5.32:dev') { transitive = false } diff --git a/src/main/java/com/glodblock/github/FluidCraft.java b/src/main/java/com/glodblock/github/FluidCraft.java index 39b06b1b..b18e3e4d 100644 --- a/src/main/java/com/glodblock/github/FluidCraft.java +++ b/src/main/java/com/glodblock/github/FluidCraft.java @@ -28,7 +28,7 @@ import cpw.mods.fml.common.network.NetworkRegistry; modid = FluidCraft.MODID, version = FluidCraft.VERSION, name = FluidCraft.MODNAME, - dependencies = "required-after:appliedenergistics2;required-after:CoFHCore;after:waila;after:thaumicenergistics;after:ae2wct") + dependencies = "required-after:appliedenergistics2;required-after:CoFHCore;required-after:Baubles;after:waila;after:thaumicenergistics;after:ae2wct") public class FluidCraft { public static final String MODID = "GRADLETOKEN_MODID"; diff --git a/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryAdaptor.java b/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryAdaptor.java index 848e641e..abe35561 100644 --- a/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryAdaptor.java +++ b/src/main/java/com/glodblock/github/inventory/FluidConvertingInventoryAdaptor.java @@ -1,9 +1,8 @@ package com.glodblock.github.inventory; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; import javax.annotation.Nullable; @@ -16,9 +15,14 @@ import net.minecraftforge.fluids.IFluidHandler; import appeng.api.config.FuzzyMode; import appeng.api.config.InsertionMode; +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; @@ -34,24 +38,47 @@ import com.glodblock.github.util.BlockPos; import com.glodblock.github.util.ModAndClassUtil; import com.glodblock.github.util.Util; +import crazypants.enderio.conduit.item.IItemConduit; +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(@Nullable InventoryAdaptor invItems, @Nullable IFluidHandler invFluids, - ForgeDirection facing, BlockPos pos, boolean isOnmi, Object eioConduct) { + ForgeDirection facing, BlockPos pos, boolean isOnmi) { this.invItems = invItems; this.invFluids = invFluids; this.side = facing; this.posInterface = pos; - this.eioDuct = eioConduct; this.onmi = isOnmi; + this.selfInterface = getInterfaceTE(pos.getTileEntity(), facing.getOpposite()); } private final InventoryAdaptor invItems; private final IFluidHandler invFluids; private final ForgeDirection side; private final BlockPos posInterface; - private final Object eioDuct; + @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) { // sometimes i wish 1.7.10 has cap system. @@ -69,31 +96,69 @@ public class FluidConvertingInventoryAdaptor extends InventoryAdaptor { if (inter instanceof TileInterface) { onmi = ((TileInterface) inter).getTargets().size() > 1; } - Object conduct = null; - if (ModAndClassUtil.COFH && capProvider instanceof IItemDuct) { - conduct = capProvider; - } - return new FluidConvertingInventoryAdaptor(item, fluid, face, new BlockPos(inter), onmi, conduct); + return new FluidConvertingInventoryAdaptor(item, fluid, face, new BlockPos(inter), onmi); } public ItemStack addItems(ItemStack toBeAdded, InsertionMode insertionMode) { FluidStack fluid = Util.getFluidFromVirtual(toBeAdded); - if (fluid != null) { - if (invFluids != null) { - if (invFluids.canFill(side, fluid.getFluid())) { - int filled = invFluids.fill(side, fluid, true); - if (filled > 0) { - fluid.amount -= filled; - return ItemFluidPacket.newStack(fluid); - } - } + 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 ItemFluidPacket.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; } - return toBeAdded; } - if (eioDuct != null) { - return ((IItemDuct) eioDuct).insertItem(side, toBeAdded); - } - return invItems != null ? invItems.addItems(toBeAdded, insertionMode) : toBeAdded; } @Override @@ -109,35 +174,56 @@ public class FluidConvertingInventoryAdaptor extends InventoryAdaptor { @Override public ItemStack simulateAdd(ItemStack toBeSimulated, InsertionMode insertionMode) { FluidStack fluid = Util.getFluidFromVirtual(toBeSimulated); - if (fluid != null) { - if (onmi) { - boolean sus = false; - for (ForgeDirection dir : ForgeDirection.values()) { - TileEntity te = posInterface.getOffSet(dir).getTileEntity(); - if (te instanceof IFluidHandler) { - int filled = ((IFluidHandler) te).fill(dir.getOpposite(), fluid, false); - if (filled > 0) { - sus = true; - break; - } + 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; } } - return sus ? null : toBeSimulated; - } - if (invFluids != null) { - int filled = invFluids.fill(side, fluid, false); - if (filled > 0) { - fluid.amount -= filled; - return ItemFluidPacket.newStack(fluid); + } 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 toBeSimulated; + return sus ? null : toBeSimulated; } - // Assert EIO conduct can hold all item, as it is the origin practice in AE2 - if (eioDuct != null) { - return null; - } - return invItems != null ? invItems.simulateAdd(toBeSimulated, insertionMode) : toBeSimulated; } @Override @@ -164,15 +250,123 @@ public class FluidConvertingInventoryAdaptor extends InventoryAdaptor { @Override public boolean containsItems() { - if (invFluids == null && invItems == null) { - // If this entity doesn't have fluid or item inventory, we just view it as full of things. - return true; + 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; } - if (invFluids != null && invFluids.getTankInfo(this.side) != null) { + boolean anyValid = false; + for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { + // Avoid sending stuff into itself me network + if (checkValidSide(this.posInterface.getOffSet(dir).getTileEntity(), dir) + && !isItemConduit(this.posInterface.getOffSet(dir).getTileEntity())) { + 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 iterator() { + return new SlotIterator( + invFluids != null ? invFluids.getTankInfo(side) : new FluidTankInfo[0], + 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) { + return ModAndClassUtil.GT5 && o instanceof TileEntity + && ((TileEntity) o).getBlockType().getUnlocalizedName().equals("gt.blockmachines"); + } + + private boolean isItemConduit(TileEntity te) { + if (ModAndClassUtil.EIO && conduitClazz.isInstance(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 && te instanceof IItemDuct; + } + + 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 (tank != null && tank.getTankInfo(direction) != null) { List tankInfos = new LinkedList<>(); - if (Util.getPart(invFluids, this.side) instanceof PartP2PLiquids) { + if (Util.getPart(tank, direction) instanceof PartP2PLiquids) { // read other ends of p2p for blocking mode - PartP2PLiquids invFluidsP2P = (PartP2PLiquids) Util.getPart(invFluids, this.side); + PartP2PLiquids invFluidsP2P = (PartP2PLiquids) Util.getPart(tank, direction); try { Iterator it = invFluidsP2P.getOutputs().iterator(); boolean checkedInput = false; @@ -191,35 +385,72 @@ public class FluidConvertingInventoryAdaptor extends InventoryAdaptor { } } catch (GridAccessException ignore) {} } else { - tankInfos.add(invFluids.getTankInfo(this.side)); + tankInfos.add(tank.getTankInfo(direction)); } boolean hasTank = false; for (FluidTankInfo[] tankInfoArray : tankInfos) { - for (FluidTankInfo tank : tankInfoArray) { + for (FluidTankInfo tankInfo : tankInfoArray) { hasTank = true; - FluidStack fluid = tank.fluid; + FluidStack fluid = tankInfo.fluid; if (fluid != null && fluid.amount > 0) { - return true; + return 1; } } } - if (!hasTank && invItems == null) { - // If this entity doesn't have fluid or item inventory, we just view it as full of things. + 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.ordinal()); + } + } + 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 = Ae2Reflect.getInterfaceProxy(other); + AENetworkProxy proxy2 = Ae2Reflect.getInterfaceProxy(self); + if (proxy1.getGrid() == proxy2.getGrid()) { + return false; + } + } catch (GridAccessException e) { return true; } } - return invItems != null && invItems.containsItems(); - } - - public boolean hasSlots() { - return (invFluids != null && invFluids.getTankInfo(side).length > 0) || (invItems != null); - } - - @Override - public Iterator iterator() { - return new SlotIterator( - invFluids != null ? invFluids.getTankInfo(side) : new FluidTankInfo[0], - invItems != null ? invItems.iterator() : Collections.emptyIterator()); + return true; } private static class SlotIterator implements Iterator { diff --git a/src/main/java/com/glodblock/github/util/Ae2Reflect.java b/src/main/java/com/glodblock/github/util/Ae2Reflect.java index 0b6412a1..645d3e37 100644 --- a/src/main/java/com/glodblock/github/util/Ae2Reflect.java +++ b/src/main/java/com/glodblock/github/util/Ae2Reflect.java @@ -16,7 +16,9 @@ import appeng.api.storage.data.IAEItemStack; 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; import appeng.me.storage.MEInventoryHandler; import appeng.me.storage.MEPassThrough; import appeng.parts.p2p.PartP2PLiquids; @@ -35,6 +37,7 @@ public class Ae2Reflect { 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 Method mItemSlot_setExtractable; private static final Method mCPU_getGrid; private static final Method mCPU_postChange; @@ -54,6 +57,7 @@ public class Ae2Reflect { 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, @@ -164,6 +168,10 @@ public class Ae2Reflect { return Ae2Reflect.readField(owner, fContainerUpgradeable_upgradeable); } + public static AENetworkProxy getInterfaceProxy(DualityInterface owner) { + return Ae2Reflect.readField(owner, fDualInterface_gridProxy); + } + public static void postCPUChange(CraftingCPUCluster cpu, IAEItemStack stack, MachineSource src) { try { mCPU_postChange.invoke(cpu, stack, src);