Package crazypants.enderio.machine.transceiver

Source Code of crazypants.enderio.machine.transceiver.TileTransceiver

package crazypants.enderio.machine.transceiver;

import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import net.minecraft.block.Block;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTankInfo;
import net.minecraftforge.fluids.IFluidHandler;
import crazypants.enderio.ModObject;
import crazypants.enderio.config.Config;
import crazypants.enderio.machine.AbstractPoweredTaskEntity;
import crazypants.enderio.machine.ContinuousTask;
import crazypants.enderio.machine.IMachineRecipe;
import crazypants.enderio.machine.IPoweredTask;
import crazypants.enderio.machine.IoMode;
import crazypants.enderio.machine.PoweredTask;
import crazypants.enderio.machine.SlotDefinition;
import crazypants.enderio.network.PacketHandler;
import crazypants.enderio.power.BasicCapacitor;
import crazypants.enderio.power.Capacitors;
import crazypants.enderio.power.ICapacitor;
import crazypants.enderio.power.PowerDistributor;
import crazypants.enderio.rail.EnderRailController;
import crazypants.util.FluidUtil;
import crazypants.util.ItemUtil;
import crazypants.vecmath.VecmathUtil;

public class TileTransceiver extends AbstractPoweredTaskEntity implements IFluidHandler {

  //Power will only be sent to other transceivers is the buffer is higher than this amount
  private static final float MIN_POWER_TO_SEND = 0.5f;

  private final EnumMap<ChannelType, List<Channel>> sendChannels = new EnumMap<ChannelType, List<Channel>>(ChannelType.class);
  private final EnumMap<ChannelType, List<Channel>> recieveChannels = new EnumMap<ChannelType, List<Channel>>(ChannelType.class);

  private ICapacitor capacitor = new BasicCapacitor(Config.transceiverMaxIoRF * 2, 500000, Config.transceiverMaxIoRF);
  private boolean sendChannelsDirty = false;
  private boolean recieveChannelsDirty = false;
  private boolean registered = false;

  private Map<ForgeDirection, IFluidHandler> neighbourFluidHandlers = null;

  private PowerDistributor powerDistributor;

  private final EnderRailController railController;

  private boolean inFluidFill = false;
  private boolean inGetTankInfo = false;

  public TileTransceiver() {
    super(new SlotDefinition(8, 8, 0));
    for (ChannelType type : ChannelType.values()) {
      sendChannels.put(type, new ArrayList<Channel>());
      recieveChannels.put(type, new ArrayList<Channel>());
    }
    currentTask = new ContinuousTask(Config.transceiverUpkeepCostRF);
    railController = new EnderRailController(this);
  }

  public EnderRailController getRailController() {
    return railController;
  }

  public boolean isRedstoneChecksPassed() {
    return redstoneCheckPassed;
  }

  @Override
  protected boolean processTasks(boolean redstoneChecksPassed) {
    boolean res = super.processTasks(redstoneChecksPassed);
    if(!redstoneChecksPassed) {
      return res;
    }

    //NB: Fluid done synchronously
    processPower();
    processItems();
    return res;
  }

  @Override
  public void updateEntity() {
    if(!registered && worldObj != null && !worldObj.isRemote) {
      ServerChannelRegister.instance.register(this);
      registered = true;
      removeUnregsiteredChannels(sendChannels);
      removeUnregsiteredChannels(recieveChannels);
    }
    super.updateEntity();

    if(worldObj != null && !worldObj.isRemote) {
      railController.doTick();
      if(sendChannelsDirty) {
        PacketHandler.sendToAllAround(new PacketSendRecieveChannelList(this, true), this, 256);
        sendChannelsDirty = false;
      }
      if(recieveChannelsDirty) {
        PacketHandler.sendToAllAround(new PacketSendRecieveChannelList(this, false), this, 256);
        recieveChannelsDirty = false;
      }
    }
  }

  @Override
  public void invalidate() {
    super.invalidate();
    if(registered && worldObj != null && !worldObj.isRemote) {
      ServerChannelRegister.instance.dergister(this);
      registered = false;
    }
  }

  @Override
  public void onChunkUnload() {
    super.onChunkUnload();
    if(registered && worldObj != null && !worldObj.isRemote) {
      ServerChannelRegister.instance.dergister(this);
      registered = false;
    }
  }

  private void removeUnregsiteredChannels(EnumMap<ChannelType, List<Channel>> channels) {
    List<Channel> toRemove = new ArrayList<Channel>();
    for (List<Channel> chans : channels.values()) {
      for (Channel chan : chans) {
        if(!ServerChannelRegister.instance.getChannelsForType(chan.getType()).contains(chan)) {
          toRemove.add(chan);
        }
      }
    }
    for (Channel chan : toRemove) {
      removeChannel(chan, channels);
    }
  }

  @Override
  public String getMachineName() {
    return ModObject.blockTransceiver.unlocalisedName;
  }

  @Override
  public boolean isActive() {
    return hasPower();
  }

  @Override
  protected boolean isMachineItemValidForSlot(int i, ItemStack itemstack) {
    return true;
  }

  @Override
  public ICapacitor getCapacitor() {
    return capacitor;
  }

  public int getPowerUsePerTick() {
    return Config.transceiverUpkeepCostRF;
  }

  public List<Channel> getSendChannels(ChannelType type) {
    return sendChannels.get(type);
  }

  public List<Channel> getRecieveChannels(ChannelType type) {
    return recieveChannels.get(type);
  }

  public void addSendChanel(Channel channel) {
    addChannel(channel, sendChannels);
  }

  public void addRecieveChanel(Channel channel) {
    addChannel(channel, recieveChannels);
  }

  public void removeSendChanel(Channel channel) {
    removeChannel(channel, sendChannels);
  }

  public void removeRecieveChanel(Channel channel) {
    removeChannel(channel, recieveChannels);
  }

  private void addChannel(Channel channel, EnumMap<ChannelType, List<Channel>> channels) {
    if(channel == null) {
      return;
    }
    List<Channel> chans = channels.get(channel.getType());
    if(!chans.contains(channel)) {
      chans.add(channel);
      if(channels == sendChannels) {
        sendChannelsDirty = true;
      } else {
        recieveChannelsDirty = true;
      }
    }

  }

  private void removeChannel(Channel channel, EnumMap<ChannelType, List<Channel>> channels) {
    if(channel == null) {
      return;
    }
    List<Channel> chans = channels.get(channel.getType());
    if(chans.contains(channel)) {
      chans.remove(channel);
      if(channels == sendChannels) {
        sendChannelsDirty = true;
      } else {
        recieveChannelsDirty = true;
      }
    }
  }

  @Override
  public void readCustomNBT(NBTTagCompound nbtRoot) {
    super.readCustomNBT(nbtRoot);
    railController.readFromNBT(nbtRoot);
    currentTask = new ContinuousTask(Config.transceiverUpkeepCostRF);
  }

  @Override
  public void writeCustomNBT(NBTTagCompound nbtRoot) {
    super.writeCustomNBT(nbtRoot);
    railController.writeToNBT(nbtRoot);
  }

  @Override
  public void readCommon(NBTTagCompound nbtRoot) {
    super.readCommon(nbtRoot);
    readChannels(nbtRoot, sendChannels, "sendChannels");
    readChannels(nbtRoot, recieveChannels, "recieveChannels");
  }

  static void readChannels(NBTTagCompound nbtRoot, EnumMap<ChannelType, List<Channel>> readInto, String key) {

    for (ChannelType type : ChannelType.values()) {
      readInto.get(type).clear();
    }

    if(!nbtRoot.hasKey(key)) {
      return;
    }
    NBTTagList tags = (NBTTagList) nbtRoot.getTag(key);
    for (int i = 0; i < tags.tagCount(); i++) {
      NBTTagCompound chanelTag = tags.getCompoundTagAt(i);
      Channel channel = Channel.readFromNBT(chanelTag);
      if(channel != null) {
        readInto.get(channel.getType()).add(channel);
      }
    }

  }

  @Override
  public void writeCommon(NBTTagCompound nbtRoot) {
    super.writeCommon(nbtRoot);

    NBTTagList channelTags = createTagList(sendChannels);
    nbtRoot.setTag("sendChannels", channelTags);

    channelTags = createTagList(recieveChannels);
    nbtRoot.setTag("recieveChannels", channelTags);
  }

  static NBTTagList createTagList(EnumMap<ChannelType, List<Channel>> chans) {
    NBTTagList res = new NBTTagList();
    for (List<Channel> chanList : chans.values()) {
      for (Channel channel : chanList) {
        NBTTagCompound chanTag = new NBTTagCompound();
        channel.writeToNBT(chanTag);
        res.appendTag(chanTag);
      }
    }
    return res;
  }

  void setSendChannels(EnumMap<ChannelType, List<Channel>> channels) {
    for (ChannelType type : ChannelType.values()) {
      sendChannels.get(type).clear();
      sendChannels.get(type).addAll(channels.get(type));
    }
  }

  void setRecieveChannels(EnumMap<ChannelType, List<Channel>> channels) {
    for (ChannelType type : ChannelType.values()) {
      recieveChannels.get(type).clear();
      recieveChannels.get(type).addAll(channels.get(type));
    }
  }

  EnumMap<ChannelType, List<Channel>> getSendChannels() {
    return sendChannels;
  }

  EnumMap<ChannelType, List<Channel>> getReceiveChannels() {
    return recieveChannels;
  }

  //---------------- Power Handling

  private void processPower() {
    List<Channel> sendTo = getSendChannels(ChannelType.POWER);
    int canSend = getMaxSendableEnergy();
    if(canSend > 0 && !sendTo.isEmpty()) {
      for (int i = 0; i < sendTo.size() && canSend > 0; i++) {
        ServerChannelRegister.instance.sendPower(this, canSend, sendTo.get(i));
        canSend = getMaxSendableEnergy();
      }
    }
    canSend = getMaxSendableEnergy();
    if(canSend > 0 && !getRecieveChannels(ChannelType.POWER).isEmpty()) {
      if(powerDistributor == null) {
        powerDistributor = new PowerDistributor(getLocation());
      }
      int used = powerDistributor.transmitEnergy(worldObj, canSend);
      usePower(used);
    }
  }

  private int getMaxSendableEnergy() {
    return getEnergyStored() - (int) (MIN_POWER_TO_SEND * getMaxEnergyStored());
  }

  private float getEnergyStoredRatio() {
    return (float) getEnergyStored() / getMaxEnergyStored();
  }

  @Override
  public void onNeighborBlockChange(Block blockId) {
    super.onNeighborBlockChange(blockId);
    if(powerDistributor != null) {
      powerDistributor.neighboursChanged();
    }
    neighbourFluidHandlers = null;
  }

  private boolean hasRecieveChannel(List<Channel> channels, ChannelType type) {
    boolean hasChannel = false;
    for (Channel chan : channels) {
      if(getRecieveChannels(type).contains(chan)) {
        hasChannel = true;
        break;
      }
    }
    return hasChannel;
  }

  //----------------  Fluid Handling

  @Override
  public boolean canFill(ForgeDirection from, Fluid fluid) {
    if(inFluidFill) {
      return false;
    }
    try {
      inFluidFill = true;
      if(getSendChannels(ChannelType.FLUID).isEmpty()) {
        return false;
      }
      return ServerChannelRegister.instance.canFill(this, getSendChannels(ChannelType.FLUID), fluid);
    } finally {
      inFluidFill = false;
    }
  }

  public boolean canReceive(List<Channel> channels, Fluid fluid) {
    if(inFluidFill) {
      return false;
    }

    if(!hasRecieveChannel(channels, ChannelType.FLUID)) {
      return false;
    }
    Map<ForgeDirection, IFluidHandler> handlers = getNeighbouringFluidHandlers();
    for (Entry<ForgeDirection, IFluidHandler> entry : handlers.entrySet()) {
      if(entry.getValue().canFill(entry.getKey().getOpposite(), fluid)) {
        return true;
      }
    }
    return false;
  }

  @Override
  public int fill(ForgeDirection from, FluidStack resource, boolean doFill) {
    if(inFluidFill) {
      return 0;
    }
    try {
      inFluidFill = true;
      if(getSendChannels(ChannelType.FLUID).isEmpty() || !redstoneCheckPassed || !getIoMode(from).canRecieveInput()) {
        return 0;
      }
      return ServerChannelRegister.instance.fill(this, getSendChannels(ChannelType.FLUID), resource, doFill);
    } finally {
      inFluidFill = false;
    }
  }

  public int recieveFluid(List<Channel> channels, FluidStack resource, boolean doFill) {
    if(inFluidFill) {
      return 0;
    }
    if(!hasRecieveChannel(channels, ChannelType.FLUID) || !redstoneCheckPassed) {
      return 0;
    }
    Map<ForgeDirection, IFluidHandler> handlers = getNeighbouringFluidHandlers();
    for (Entry<ForgeDirection, IFluidHandler> entry : handlers.entrySet()) {
      IoMode mode = getIoMode(entry.getKey());
      if(mode.canOutput()) {
        int res = entry.getValue().fill(entry.getKey().getOpposite(), resource, doFill);
        if(res > 0) {
          return res;
        }
      }
    }
    return 0;
  }

  @Override
  public FluidTankInfo[] getTankInfo(ForgeDirection from) {
    if(inGetTankInfo) {
      return new FluidTankInfo[0];
    }
    try {
      inGetTankInfo = true;
      return ServerChannelRegister.instance.getTankInfoForChannels(this, getSendChannels(ChannelType.FLUID));
    } finally {
      inGetTankInfo = false;
    }
  }

  public void getRecieveTankInfo(List<FluidTankInfo> infos, List<Channel> channels) {
    if(inGetTankInfo) {
      return;
    }
    try {
      inGetTankInfo = true;
      if(!hasRecieveChannel(channels, ChannelType.FLUID)) {
        return;
      }
      Map<ForgeDirection, IFluidHandler> fluidHandlers = getNeighbouringFluidHandlers();
      for (Entry<ForgeDirection, IFluidHandler> entry : fluidHandlers.entrySet()) {
        FluidTankInfo[] tanks = entry.getValue().getTankInfo(entry.getKey().getOpposite());
        if(tanks != null) {
          for (FluidTankInfo info : tanks) {
            infos.add(info);
          }
        }
      }
    } finally {
      inGetTankInfo = false;
    }
  }

  Map<ForgeDirection, IFluidHandler> getNeighbouringFluidHandlers() {
    if(neighbourFluidHandlers == null) {
      neighbourFluidHandlers = FluidUtil.getNeighbouringFluidHandlers(worldObj, getLocation());
    }
    return neighbourFluidHandlers;
  }

  //Pulling liquids not supported
  @Override
  public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) {
    return null;
  }

  @Override
  public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) {
    return null;
  }

  @Override
  public boolean canDrain(ForgeDirection from, Fluid fluid) {
    return false;
  }

  //---------------- item handling
  private void processItems() {
    List<Channel> sendItemChannels = getSendChannels(ChannelType.ITEM);
    if(!sendItemChannels.isEmpty()) {
      for (int i = slotDefinition.minInputSlot; i <= slotDefinition.maxInputSlot; i++) {
        ItemStack toSend = getStackInSlot(i);
        if(toSend != null) {
          ServerChannelRegister.instance.sendItem(this, sendItemChannels, i, toSend);
        }
      }
    }
  }

  @Override
  public boolean canInsertItem(int slot, ItemStack itemstack, int j) {
    if(itemstack == null) {
      return false;
    }

    //only allow 1 stack per type
    if(slotDefinition.isInputSlot(slot)) {
      for (int i = slotDefinition.getMinInputSlot(); i <= slotDefinition.getMaxInputSlot(); i++) {
        if(i != slot) {
          if(ItemUtil.areStacksEqual(itemstack, getStackInSlot(i))) {
            return false;
          }
        }
      }
    } else if(slotDefinition.isOutputSlot(slot)) {
      for (int i = slotDefinition.getMinOutputSlot(); i <= slotDefinition.getMaxOutputSlot(); i++) {
        if(i != slot) {
          if(ItemUtil.areStacksEqual(itemstack, getStackInSlot(i))) {
            return false;
          }
        }
      }
    }
    return super.canInsertItem(slot, itemstack, j);
  }

}
TOP

Related Classes of crazypants.enderio.machine.transceiver.TileTransceiver

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.