Package crazypants.enderio.conduit.item

Source Code of crazypants.enderio.conduit.item.NetworkedInventory

package crazypants.enderio.conduit.item;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityChest;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import crazypants.enderio.conduit.ConnectionMode;
import crazypants.enderio.conduit.item.filter.IItemFilter;
import crazypants.enderio.config.Config;
import crazypants.util.BlockCoord;
import crazypants.util.InventoryWrapper;
import crazypants.util.ItemUtil;
import crazypants.util.RoundRobinIterator;

public class NetworkedInventory {

  private ISidedInventory inv;
  IItemConduit con;
  ForgeDirection conDir;
  BlockCoord location;
  int inventorySide;

  List<Target> sendPriority = new ArrayList<Target>();
  RoundRobinIterator<Target> rrIter = new RoundRobinIterator<Target>(sendPriority);

  private int extractFromSlot = -1;

  int tickDeficit;

  //work around for a vanilla chest changing into a double chest without doing unneeded checks all the time
  boolean recheckInv = false;
  //Hack for TiC crafting station not working correctly when setting output slot to null
  boolean ticHack = false;

  World world;
  ItemConduitNetwork network;

  NetworkedInventory(ItemConduitNetwork network, IInventory inv, IItemConduit con, ForgeDirection conDir, BlockCoord location) {
    this.network = network;
    inventorySide = conDir.getOpposite().ordinal();

    this.con = con;
    this.conDir = conDir;
    this.location = location;
    world = con.getBundle().getWorld();

    TileEntity te = world.getTileEntity(location.x, location.y, location.z);
    if(te.getClass().getName().equals("tconstruct.tools.logic.CraftingStationLogic")) {
      ticHack = true;
    } else if(te.getClass().getName().contains("cpw.mods.ironchest")) {
      recheckInv = true;
    } else if(te instanceof TileEntityChest) {
      recheckInv = true;
    }
    updateInventory();
  }

  public boolean hasTarget(IItemConduit conduit, ForgeDirection dir) {
    for (Target t : sendPriority) {
      if(t.inv.con == conduit && t.inv.conDir == dir) {
        return true;
      }
    }
    return false;
  }

  boolean canExtract() {
    ConnectionMode mode = con.getConnectionMode(conDir);
    return mode == ConnectionMode.INPUT || mode == ConnectionMode.IN_OUT;
  }

  boolean canInsert() {
    ConnectionMode mode = con.getConnectionMode(conDir);
    return mode == ConnectionMode.OUTPUT || mode == ConnectionMode.IN_OUT;
  }

  boolean isSticky() {
    return con.getOutputFilter(conDir) != null && con.getOutputFilter(conDir).isValid() && con.getOutputFilter(conDir).isSticky();
  }

  int getPriority() {
    return con.getOutputPriority(conDir);
  }

  public void onTick(long tick) {
    int transfered;
    if(tickDeficit > 0 || !canExtract() || !con.isExtractionRedstoneConditionMet(conDir)) {
      //do nothing    
    } else {
      transferItems();
    }

    tickDeficit--;
    if(tickDeficit < -1) {
      //Sleep for a second before checking again.
      tickDeficit = 20;
    }
  }

  private boolean canExtractThisTick(long tick) {
    if(!con.isExtractionRedstoneConditionMet(conDir)) {
      return false;
    }
    return true;
  }

  private int nextSlot(int numSlots) {
    ++extractFromSlot;
    if(extractFromSlot >= numSlots || extractFromSlot < 0) {
      extractFromSlot = 0;
    }
    return extractFromSlot;
  }

  private void setNextStartingSlot(int slot) {
    extractFromSlot = slot;
    extractFromSlot--;
  }

  private boolean transferItems() {

    if(recheckInv) {
      updateInventory();
    }

    int[] slotIndices = getInventory().getAccessibleSlotsFromSide(inventorySide);
    if(slotIndices == null) {
      return false;
    }
    int numSlots = slotIndices.length;
    ItemStack extractItem = null;
    int maxExtracted = con.getMaximumExtracted(conDir);

    int slot = -1;
    int slotChecksPerTick = Math.min(numSlots, ItemConduitNetwork.MAX_SLOT_CHECK_PER_TICK);
    for (int i = 0; i < slotChecksPerTick; i++) {
      int index = nextSlot(numSlots);
      slot = slotIndices[index];
      ItemStack item = getInventory().getStackInSlot(slot);
      if(canExtractItem(item)) {
        extractItem = item.copy();
        if(getInventory().canExtractItem(slot, extractItem, inventorySide)) {
          if(doTransfer(extractItem, slot, maxExtracted)) {
            setNextStartingSlot(slot);
            return true;
          }
        }
      }
    }
    return false;
  }

  private boolean canExtractItem(ItemStack itemStack) {
    if(itemStack == null) {
      return false;
    }
    IItemFilter filter = con.getInputFilter(conDir);
    if(filter == null) {
      return true;
    }
    return filter.doesItemPassFilter(this, itemStack);
  }

  private boolean doTransfer(ItemStack extractedItem, int slot, int maxExtract) {
    if(extractedItem == null || extractedItem.getItem() == null) {
      return false;
    }
    ItemStack toExtract = extractedItem.copy();
    toExtract.stackSize = Math.min(maxExtract, toExtract.stackSize);
    int numInserted = insertIntoTargets(toExtract);
    if(numInserted <= 0) {
      return false;
    }
    ItemStack curStack = getInventory().getStackInSlot(slot);
    if(curStack != null) {
      if(ticHack) {
        getInventory().decrStackSize(slot, numInserted);
        getInventory().markDirty();
      } else {
        curStack = curStack.copy();
        curStack.stackSize -= numInserted;
        if(curStack.stackSize > 0) {
          getInventory().setInventorySlotContents(slot, curStack);
          getInventory().markDirty();         
        } else {
          getInventory().setInventorySlotContents(slot, null);
          getInventory().markDirty();
        }
      }
    }
    con.itemsExtracted(numInserted, slot);
    tickDeficit = Math.round(numInserted * con.getTickTimePerItem(conDir));
    return true;

  }

  int insertIntoTargets(ItemStack toExtract) {
    if(toExtract == null) {
      return 0;
    }

    int totalToInsert = toExtract.stackSize;
    int leftToInsert = totalToInsert;
    boolean matchedStickyInput = false;

    Iterable<Target> targets = getTargetIterator();

    //for (Target target : sendPriority) {
    for (Target target : targets) {
      if(target.stickyInput && !matchedStickyInput) {
        IItemFilter of = target.inv.con.getOutputFilter(target.inv.conDir);
        matchedStickyInput = of != null && of.isValid() && of.doesItemPassFilter(this, toExtract);
      }
      if(target.stickyInput || !matchedStickyInput) {
        if(target.inv.recheckInv) {
          target.inv.updateInventory();
        }
        int inserted = target.inv.insertItem(toExtract);
        if(inserted > 0) {
          toExtract.stackSize -= inserted;
          leftToInsert -= inserted;
        }
        if(leftToInsert <= 0) {
          return totalToInsert;
        }
      }
    }
    return totalToInsert - leftToInsert;
  }

  private Iterable<Target> getTargetIterator() {
    if(con.isRoundRobinEnabled(conDir)) {
      return rrIter;
    }
    return sendPriority;
  }

  private void updateInventory() {

    TileEntity te = world.getTileEntity(location.x, location.y, location.z);
    if(te instanceof ISidedInventory) {
      inv = (ISidedInventory) te;
    } else if(te instanceof IInventory) {
      inv = new InventoryWrapper((IInventory) te);
    }
  }

  private int insertItem(ItemStack item) {
    if(!canInsert() || item == null) {
      return 0;
    }
    IItemFilter filter = con.getOutputFilter(conDir);
    if(filter != null) {
      if(!filter.doesItemPassFilter(this, item)) {
        return 0;
      }
    }
    return ItemUtil.doInsertItem(getInventory(), item, ForgeDirection.values()[inventorySide]);
  }

  void updateInsertOrder() {
    sendPriority.clear();
    if(!canExtract()) {
      return;
    }
    List<Target> result = new ArrayList<NetworkedInventory.Target>();

    for (NetworkedInventory other : network.inventories) {
      if((con.isSelfFeedEnabled(conDir) || (other != this))
          && other.canInsert()
          && con.getInputColor(conDir) == other.con.getOutputColor(other.conDir)) {

        if(Config.itemConduitUsePhyscialDistance) {
          sendPriority.add(new Target(other, distanceTo(other), other.isSticky(), other.getPriority()));
        } else {
          result.add(new Target(other, 9999999, other.isSticky(), other.getPriority()));
        }
      }
    }

    if(Config.itemConduitUsePhyscialDistance) {
      Collections.sort(sendPriority);
    } else {
      if(!result.isEmpty()) {
        Map<BlockCoord, Integer> visited = new HashMap<BlockCoord, Integer>();
        List<BlockCoord> steps = new ArrayList<BlockCoord>();
        steps.add(con.getLocation());
        calculateDistances(result, visited, steps, 0);

        sendPriority.addAll(result);

        Collections.sort(sendPriority);
      }
    }

  }

  private void calculateDistances(List<Target> targets, Map<BlockCoord, Integer> visited, List<BlockCoord> steps, int distance) {
    if(steps == null || steps.isEmpty()) {
      return;
    }

    ArrayList<BlockCoord> nextSteps = new ArrayList<BlockCoord>();
    for (BlockCoord bc : steps) {
      IItemConduit con = network.conMap.get(bc);
      if(con != null) {
        for (ForgeDirection dir : con.getExternalConnections()) {
          Target target = getTarget(targets, con, dir);
          if(target != null && target.distance > distance) {
            target.distance = distance;
          }
        }

        if(!visited.containsKey(bc)) {
          visited.put(bc, distance);
        } else {
          int prevDist = visited.get(bc);
          if(prevDist <= distance) {
            continue;
          }
          visited.put(bc, distance);
        }

        for (ForgeDirection dir : con.getConduitConnections()) {
          nextSteps.add(bc.getLocation(dir));
        }
      }
    }
    calculateDistances(targets, visited, nextSteps, distance + 1);
  }

  private Target getTarget(List<Target> targets, IItemConduit con, ForgeDirection dir) {
    if(targets == null || con == null || con.getLocation() == null) {
      return null;
    }
    for (Target target : targets) {
      BlockCoord targetConLoc = null;
      if(target != null && target.inv != null && target.inv.con != null) {
        targetConLoc = target.inv.con.getLocation();
      }
      if(targetConLoc != null && target.inv.conDir == dir && targetConLoc.equals(con.getLocation())) {
        return target;
      }
    }
    return null;
  }

  private int distanceTo(NetworkedInventory other) {
    return con.getLocation().distanceSquared(other.con.getLocation());
  }

  public ISidedInventory getInventory() {
    return inv;
  }

  public int getInventorySide() {
    return inventorySide;
  }

  public void setInventorySide(int inventorySide) {
    this.inventorySide = inventorySide;
  }

  static class Target implements Comparable<Target> {
    NetworkedInventory inv;
    int distance;
    boolean stickyInput;
    int priority;

    Target(NetworkedInventory inv, int distance, boolean stickyInput, int priority) {
      this.inv = inv;
      this.distance = distance;
      this.stickyInput = stickyInput;
      this.priority = priority;
    }

    @Override
    public int compareTo(Target o) {
      if(stickyInput && !o.stickyInput) {
        return -1;
      }
      if(!stickyInput && o.stickyInput) {
        return 1;
      }
      if(priority != o.priority) {
        return ItemConduitNetwork.compare(o.priority, priority);
      }
      return ItemConduitNetwork.compare(distance, o.distance);
    }

  }
}
TOP

Related Classes of crazypants.enderio.conduit.item.NetworkedInventory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.