package com.austinv11.peripheralsplusplus.tiles; import appeng.api.AEApi; import appeng.api.config.Actionable; import appeng.api.networking.*; import appeng.api.networking.crafting.ICraftingCallback; import appeng.api.networking.crafting.ICraftingGrid; import appeng.api.networking.crafting.ICraftingJob; import appeng.api.networking.security.IActionHost; import appeng.api.networking.security.MachineSource; import appeng.api.networking.storage.IStorageGrid; import appeng.api.storage.IMEMonitor; import appeng.api.storage.data.IAEItemStack; import appeng.api.util.AECableType; import appeng.api.util.AEColor; import appeng.api.util.DimensionalCoord; import appeng.core.WorldSettings; import com.austinv11.peripheralsplusplus.init.ModBlocks; import com.austinv11.peripheralsplusplus.reference.Config; import cpw.mods.fml.common.Optional; import cpw.mods.fml.common.registry.GameRegistry; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import net.minecraft.block.Block; import net.minecraft.block.BlockContainer; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.common.util.ForgeDirection; import java.util.*; @Optional.InterfaceList(value = {@Optional.Interface(modid="appliedenergistics2",iface="appeng.api.networking.security.IActionHost", striprefs=true), @Optional.Interface(modid="appliedenergistics2",iface="appeng.api.networking.IGridBlock", striprefs=true)}) public class TileEntityMEBridge extends MountedTileEntity implements IActionHost, IGridBlock { public static String publicName = "meBridge"; private String name = "tileEntityMEBridge"; private HashMap<IComputerAccess, Boolean> computers = new HashMap<IComputerAccess,Boolean>(); private IGridNode node; private boolean initialized = false; public EntityPlayer placed; public TileEntityMEBridge() { super(); } public String getName() { return name; } @Override public void readFromNBT(NBTTagCompound nbttagcompound) { super.readFromNBT(nbttagcompound); if (node != null) node.destroy(); node = AEApi.instance().createGridNode(this); node.loadFromNBT("node", nbttagcompound); initialized = false; } @Override public void writeToNBT(NBTTagCompound nbttagcompound) { super.writeToNBT(nbttagcompound); if (node != null) node.saveToNBT("node", nbttagcompound); } @Override public void updateEntity() { if (!worldObj.isRemote) if (!initialized) { if (placed != null) getNode().setPlayerID(WorldSettings.getInstance().getPlayerID(placed.getGameProfile())); getNode().updateState(); initialized = true; } } @Override public String getType() { return publicName; } @Override public String[] getMethodNames() { return new String[]{"listAll", "listItems", "listCraft", "retrieve", "craft"}; } @Override public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws LuaException, InterruptedException { if (!Config.enableMEBridge) throw new LuaException("ME Bridges have been disabled"); IMEMonitor<IAEItemStack> monitor = ((IStorageGrid) node.getGrid().getCache(IStorageGrid.class)).getItemInventory(); // try { switch (method) { case 0: return new Object[]{iteratorToMap(monitor.getStorageList().iterator(), 0)}; case 1: return new Object[]{iteratorToMap(monitor.getStorageList().iterator(), 1)}; case 2: return new Object[]{iteratorToMap(monitor.getStorageList().iterator(), 2)}; case 3: ForgeDirection dir; if (arguments.length < 3) throw new LuaException("Too few arguments"); if (!(arguments[0] instanceof String)) throw new LuaException("Bad argument #1 (expected string)"); if (!(arguments[1] instanceof Double)) throw new LuaException("Bad argument #2 (expected number"); if (!(arguments[2] instanceof String) && !(arguments[2] instanceof Double)) throw new LuaException("Bad argument #3 (expected string or number)"); Item item = GameRegistry.findItem(((String) arguments[0]).split(":")[0], ((String) arguments[0]).split(":")[1].split(" ")[0]); long amount = (long) (int) (double) (Double) arguments[1]; if (arguments[2] instanceof String) dir = ForgeDirection.valueOf(((String) arguments[2]).toUpperCase()); else dir = ForgeDirection.getOrientation((int) (double) (Double) arguments[2]); if (!isInventoryOnSide(dir)) throw new LuaException("Block is not a valid inventory"); IInventory inventory = getInventoryForSide(dir); long extracted = 0; int meta = ((String) arguments[0]).contains(" ") ? Integer.valueOf(((String)arguments[0]).split(" ")[1]) : 0; IAEItemStack stack = findAEStackFromItemStack(monitor, new ItemStack(item, 1, meta)); if (stack != null) { if (amount > stack.getStackSize()) amount = stack.getStackSize(); if (amount > getRemainingSlots(item, inventory)) amount = getRemainingSlots(item, inventory); IAEItemStack stackToGet = stack.copy(); stackToGet.setStackSize(amount); IAEItemStack resultant = monitor.extractItems(stackToGet, Actionable.MODULATE, new MachineSource(this)); if (resultant != null) { extracted = resultant.getStackSize(); int[] slots = inventory instanceof ISidedInventory ? ((ISidedInventory) inventory).getAccessibleSlotsFromSide(dir.getOpposite().flag) : getDefaultSlots(inventory); int currentSlot = 0; while (!(resultant.getStackSize() < 1) && currentSlot < slots.length) { if (inventory.isItemValidForSlot(slots[currentSlot], new ItemStack(resultant.getItem()))) { if (inventory.getStackInSlot(slots[currentSlot]) == null) { ItemStack toAdd = resultant.getItemStack(); int stackSize = (int) (resultant.getStackSize() <= inventory.getInventoryStackLimit() ? resultant.getStackSize() : inventory.getInventoryStackLimit()); toAdd.stackSize = stackSize; inventory.setInventorySlotContents(slots[currentSlot], toAdd); resultant.setStackSize(resultant.getStackSize()-stackSize); } else { ItemStack current = inventory.getStackInSlot(slots[currentSlot]); ItemStack toAdd = resultant.getItemStack(); if (current.isItemEqual(toAdd)) { int stackSize = (int) (resultant.getStackSize()+current.stackSize <= inventory.getInventoryStackLimit() ? resultant.getStackSize()+current.stackSize : inventory.getInventoryStackLimit()); int change = stackSize - current.stackSize; current.stackSize = stackSize; inventory.setInventorySlotContents(slots[currentSlot], current); resultant.setStackSize(resultant.getStackSize()-change); } } inventory.markDirty(); } currentSlot++; } } } return new Object[]{extracted}; case 4: if (arguments.length < 2) throw new LuaException("Too few arguments"); if (!(arguments[0] instanceof String)) throw new LuaException("Bad argument #1 (expected string)"); if (!(arguments[1] instanceof Double)) throw new LuaException("Bad argument #2 (expected number"); final ICraftingGrid craftingGrid = node.getGrid().getCache(ICraftingGrid.class); Item toCraft = GameRegistry.findItem(((String) arguments[0]).split(":")[0], ((String) arguments[0]).split(":")[1].split(" ")[0]); int meta_ = ((String) arguments[0]).contains(" ") ? Integer.valueOf(((String)arguments[0]).split(" ")[1]) : 0; IAEItemStack aeToCraft_ = findAEStackFromItemStack(monitor, new ItemStack(toCraft, 1, meta_)); if (aeToCraft_ != null && aeToCraft_.isCraftable()) { IAEItemStack aeToCraft = aeToCraft_.copy(); aeToCraft.setStackSize((long) (int) (double) (Double) arguments[1]); synchronized (this) { craftingGrid.beginCraftingJob(worldObj, node.getGrid(), new MachineSource(this), aeToCraft, new ICraftingCallback() { @Override public void calculationComplete(ICraftingJob job) { craftingGrid.submitJob(job, null, null, false, new MachineSource((IActionHost) getMachine())); for (IComputerAccess comp : computers.keySet()) comp.queueEvent("craftingComplete", new Object[]{Item.itemRegistry.getNameForObject(job.getOutput().getItem()), job.getOutput().getStackSize(), job.getByteTotal()}); } }); } } return new Object[]{}; } // } catch (Exception e) { // e.printStackTrace(); // } return new Object[0]; } private int[] getDefaultSlots(IInventory inventory) { int[] array = new int[inventory.getSizeInventory()]; for (int i = 0; i < inventory.getSizeInventory(); i++) array[i] = i; return array; } private boolean isInventoryOnSide(ForgeDirection dir) { if (!worldObj.isAirBlock(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ)) { Block block = worldObj.getBlock(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ); if (block instanceof BlockContainer || block instanceof IInventory) return true; if (block.hasTileEntity(worldObj.getBlockMetadata(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ))) { return worldObj.getTileEntity(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ) instanceof IInventory; } } return false; } private IInventory getInventoryForSide(ForgeDirection dir) { if (!worldObj.isAirBlock(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ)) { Block block = worldObj.getBlock(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ); if (block instanceof IInventory) { return (IInventory) block; } if (block instanceof BlockContainer && block.hasTileEntity(worldObj.getBlockMetadata(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ))) return (IInventory)worldObj.getTileEntity(xCoord+dir.offsetX, yCoord+dir.offsetY, zCoord+dir.offsetZ); } return null; } private int getRemainingSlots(Item item, IInventory inventory) { int slots = 0; for (int i = 0; i < inventory.getSizeInventory(); i++) { if (inventory.isItemValidForSlot(i, new ItemStack(item)) && inventory.getStackInSlot(i) == null) slots += inventory.getInventoryStackLimit(); else if (inventory.isItemValidForSlot(i, new ItemStack(item)) && inventory.getStackInSlot(i).getItem() == item && (inventory.getInventoryStackLimit() >= inventory.getStackInSlot(i).stackSize)) slots += inventory.getInventoryStackLimit() - inventory.getStackInSlot(i).stackSize; } return slots; } @Override public void attach(IComputerAccess computer) { computers.put(computer, true); super.attach(computer); } @Override public void detach(IComputerAccess computer) { computers.remove(computer); super.detach(computer); } @Override public boolean equals(IPeripheral other) { return (this == other); } @Override public void invalidate() { super.invalidate(); if (node != null) { node.destroy(); node = null; initialized = false; } } private IAEItemStack findAEStackFromItemStack(IMEMonitor<IAEItemStack> monitor, ItemStack item) { IAEItemStack stack = null; for (IAEItemStack temp : monitor.getStorageList()) { if (temp.isSameType(item)) { stack = temp; break; } } return stack; } private HashMap<Integer, Object> iteratorToMap(Iterator<IAEItemStack> iterator, int flag) { HashMap<Integer,Object> map = new HashMap<Integer,Object>(); int i = 1; while (iterator.hasNext()) { Object o = getObjectFromStack(iterator.next(), flag); if (o != null) map.put(i++, o); } return map; } private Object getObjectFromStack(IAEItemStack stack, int flag) { HashMap<String, Object> map = new HashMap<String, Object>(); String itemName = Item.itemRegistry.getNameForObject(stack.getItem()); int meta = stack.getItemDamage(); long amount = stack.getStackSize(); String displayName = stack.getItemStack().getDisplayName(); map.put("name", itemName); map.put("meta", meta); map.put("amount", amount); map.put("displayName", displayName); if (flag == 0) { return map; } else if (flag == 1) { if (stack.getStackSize() > 0) return map; } else if (flag == 2) { if (stack.isCraftable()) return map; } return null; } private IGridNode getNode() { if (worldObj == null || worldObj.isRemote) return null; return node = AEApi.instance().createGridNode(this); } @Override public double getIdlePowerUsage() { return 1; } @Override public EnumSet<GridFlags> getFlags() { return EnumSet.of(GridFlags.REQUIRE_CHANNEL); } @Override public boolean isWorldAccessible() { return true; } @Override public DimensionalCoord getLocation() { return new DimensionalCoord(this); } @Override public AEColor getGridColor() { return AEColor.Transparent; } @Override public void onGridNotification(GridNotification notification) { for (IComputerAccess computer : computers.keySet()) computer.queueEvent("gridNotification", new Object[]{notification.toString()}); } @Override public void setNetworkStatus(IGrid grid, int channelsInUse) { } @Override public EnumSet<ForgeDirection> getConnectableSides() { return EnumSet.allOf(ForgeDirection.class); } @Override public IGridHost getMachine() { return this; } @Override public void gridChanged() { for (IComputerAccess computer : computers.keySet()) computer.queueEvent("gridChanged", new Object[0]); } @Override public ItemStack getMachineRepresentation() { return new ItemStack(ModBlocks.meBridge); } @Override public IGridNode getGridNode(ForgeDirection dir) { return node; } @Override public AECableType getCableConnectionType(ForgeDirection dir) { return AECableType.COVERED; } @Override public void securityBreak() { for (IComputerAccess computer : computers.keySet()) computer.queueEvent("securityBreak", new Object[0]); worldObj.setBlockToAir(xCoord, yCoord, zCoord); } @Override public IGridNode getActionableNode() { return node; } }