Package erogenousbeef.bigreactors.common.multiblock.tileentity

Source Code of erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorRedNetPort

package erogenousbeef.bigreactors.common.multiblock.tileentity;

import net.minecraft.block.Block;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import powercrystals.minefactoryreloaded.api.rednet.IRedNetInputNode;
import powercrystals.minefactoryreloaded.api.rednet.IRedNetNetworkContainer;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import erogenousbeef.bigreactors.client.gui.GuiReactorRedNetPort;
import erogenousbeef.bigreactors.common.BRLog;
import erogenousbeef.bigreactors.common.BigReactors;
import erogenousbeef.bigreactors.common.multiblock.MultiblockReactor;
import erogenousbeef.bigreactors.common.multiblock.block.BlockReactorPart;
import erogenousbeef.bigreactors.common.multiblock.interfaces.INeighborUpdatableEntity;
import erogenousbeef.bigreactors.common.multiblock.interfaces.ITickableMultiblockPart;
import erogenousbeef.bigreactors.gui.container.ContainerBasic;
import erogenousbeef.bigreactors.net.helpers.RedNetChange;
import erogenousbeef.core.common.CoordTriplet;
import erogenousbeef.core.multiblock.MultiblockControllerBase;

public class TileEntityReactorRedNetPort extends TileEntityReactorPart implements ITickableMultiblockPart, INeighborUpdatableEntity {

  public enum CircuitType {
    DISABLED,
    inputActive,         // Input: reactor on/off
    inputSetControlRod,     // Input: control rod insertion (0-100)
    inputEjectWaste,      // Input: eject waste from the reactor

    outputFuelTemperature,    // Output: Temperature of the reactor fuel
    outputCasingTemperature,  // Output: Temperature of the reactor casing
    outputFuelMix,     // Output: Fuel mix, % of contents that is fuel (0-100, 100 = 100% fuel)
    outputFuelAmount,   // Output: Fuel amount in a control rod, raw value, (0-4*height)
    outputWasteAmount,   // Output: Waste amount in a control rod, raw value, (0-4*height)
    outputEnergyAmount; // Output: Energy in the reactor's buffer, percentile (0-100, 100 = 100% full)
   
    public static final CircuitType[] s_Types = CircuitType.values();
   
    public static boolean hasCoordinate(TileEntityReactorRedNetPort.CircuitType circuitType) {
      return circuitType == CircuitType.inputSetControlRod;
    }

    public static boolean canBeToggledBetweenPulseAndNormal(CircuitType circuitType) {
      return circuitType == CircuitType.inputActive;
    }
  }

  protected final static int minInputEnumValue = CircuitType.inputActive.ordinal();
  protected final static int maxInputEnumValue = CircuitType.inputEjectWaste.ordinal();
  protected final static int minOutputEnumValue = CircuitType.outputFuelTemperature.ordinal();
  protected final static int maxOutputEnumValue = CircuitType.outputEnergyAmount.ordinal();

  protected CircuitType[] channelCircuitTypes;
  protected CoordTriplet[] coordMappings;
  protected boolean[] inputActivatesOnPulse;
  protected int[] oldValue;

  public final static int numChannels = 16;
 
  IRedNetNetworkContainer redNetwork;
  IRedNetInputNode redNetInput;

  int ticksSinceLastUpdate;
 
  public TileEntityReactorRedNetPort() {
    super();
   
    channelCircuitTypes = new CircuitType[numChannels];
    coordMappings = new CoordTriplet[numChannels];
    inputActivatesOnPulse = new boolean[numChannels];
    oldValue = new int[numChannels];

    for(int i = 0; i < numChannels; i++) {
      channelCircuitTypes[i] = CircuitType.DISABLED;
      coordMappings[i] = null;
      inputActivatesOnPulse[i] = false;
      oldValue[i] = 0;
    }
   
    redNetwork = null;
    redNetInput = null;

    ticksSinceLastUpdate = 0;
  }
 
  // IMultiblockPart
  @Override
  public void onAttached(MultiblockControllerBase newController) {
    super.onAttached(newController);

    if(this.worldObj.isRemote) { return; }
   
    checkForConnections(this.worldObj, xCoord, yCoord, zCoord);
  }
 
  @Override
  public void onMachineAssembled(MultiblockControllerBase multiblockController) {
    super.onMachineAssembled(multiblockController);

    if(this.worldObj.isRemote) { return; }
   
    checkForConnections(this.worldObj, xCoord, yCoord, zCoord);
  }

  @Override
  @SideOnly(Side.CLIENT)
  public Object getGuiElement(InventoryPlayer inventoryPlayer) {
    return new GuiReactorRedNetPort(new ContainerBasic(), this);
  }
 
  @Override
  public Object getContainer(InventoryPlayer inventoryPlayer) {
    return new ContainerBasic();
  }

  @Override
  public void writeToNBT(NBTTagCompound par1NBTTagCompound)
  {
    super.writeToNBT(par1NBTTagCompound);
    encodeSettings(par1NBTTagCompound);
  }
 
  @Override
  protected void encodeDescriptionPacket(NBTTagCompound packetData) {
    super.encodeDescriptionPacket(packetData);
    encodeSettings(packetData);
  }
 
  @Override
  public void readFromNBT(NBTTagCompound par1NBTTagCompound)
  {
    super.readFromNBT(par1NBTTagCompound);
    decodeSettings(par1NBTTagCompound);
  }
 
  @Override
  protected void decodeDescriptionPacket(NBTTagCompound packetData) {
    super.decodeDescriptionPacket(packetData);
    decodeSettings(packetData);
  }

  // RedNet API
  public int[] getOutputValues() {
    int[] outputs = new int[numChannels];
    for(int i = 0; i < numChannels; i++) {
      outputs[i] = getValueForChannel(i);
    }
   
    return outputs;
  }
 
  public int getValueForChannel(int channel) {
    if(channel < 0 || channel >= numChannels) { return 0; }
   
    if(!this.isConnected()) { return 0; }
   
    TileEntity te = null;
   
    switch(channelCircuitTypes[channel]) {
    case outputFuelTemperature:
      return (int)Math.floor(getReactorController().getFuelHeat());
    case outputCasingTemperature:
      return (int)Math.floor(getReactorController().getReactorHeat());
    case outputFuelMix:
      MultiblockReactor controller = getReactorController();
      return (int)Math.floor(((float)controller.getFuelAmount() / (float)controller.getCapacity())*100.0f);
    case outputFuelAmount:
      return getReactorController().getFuelAmount();
    case outputWasteAmount:
      return getReactorController().getWasteAmount();
    case outputEnergyAmount:
      int energyStored, energyTotal;
      MultiblockReactor reactor = this.getReactorController();
      if(reactor != null) {
        return reactor.getEnergyStoredPercentage();
      }
      return 0;
    default:
      return 0;
    }
  }
 
  public void onInputValuesChanged(int[] newValues) {
    for(int i = 0; i < newValues.length; i++) {
      onInputValueChanged(i, newValues[i]);
    }
  }
 
  public void onInputValueChanged(int channel, int newValue) {
    if(channel < 0 || channel >= numChannels) { return; }
    CircuitType type = channelCircuitTypes[channel];
    if(!isInput(type)) { return; }
    if(!this.isConnected()) { return; }
   
    if(newValue == oldValue[channel]) { return; }
    boolean isPulse = (oldValue[channel] == 0 && newValue != 0);
   
    MultiblockReactor reactor = null;
    switch(type) {
    case inputActive:
      reactor = getReactorController();
      if(inputActivatesOnPulse[channel]) {
        if(isPulse) {
          reactor.setActive(!reactor.getActive());
        }
      }
      else {
        boolean newActive = newValue != 0;
        if(newActive != reactor.getActive()) {
          reactor.setActive(newActive);
        }
      }
      break;
    case inputSetControlRod:
      // This doesn't make sense for pulsing
      newValue = Math.min(100, Math.max(0, newValue)); // Clamp to 0..100
      if(newValue == oldValue[channel]) { return; }

      if(coordMappings[channel] != null) {
        setControlRodInsertion(channel, coordMappings[channel], newValue);
      }
      else {
        reactor = getReactorController();
        reactor.setAllControlRodInsertionValues(newValue);
      }
      break;
    case inputEjectWaste:
      // This only makes sense for pulsing
      if(isPulse) {
        reactor = getReactorController();
        reactor.ejectWaste(false, null);
      }
    default:
      break;
    }
   
    oldValue[channel] = newValue;
  }
 
  // Public RedNet helpers for GUI & updates
  @Override
  public void onNeighborBlockChange(World world, int x, int y, int z, Block neighborBlock) {
    checkForConnections(world, x, y, z);
  }
 
  @Override
  public void onNeighborTileChange(IBlockAccess world, int x, int y, int z, int neighborX, int neighborY, int neighborZ) {
    checkForConnections(world, x, y, z);
  }
 
  /**
   * Updates the connected RedNet network, if there is one.
   * Will only send one update per N ticks, where N is a configurable setting.
   */
  public void onMultiblockServerTick() {
    if(!this.isConnected()) { return; }

    ticksSinceLastUpdate++;
    if(ticksSinceLastUpdate < BigReactors.ticksPerRedstoneUpdate) { return; }

    ForgeDirection out = getOutwardsDir();
   
    if(redNetwork != null) {
        redNetwork.updateNetwork(worldObj, xCoord+out.offsetX, yCoord+out.offsetY, zCoord+out.offsetZ, out.getOpposite());
    }
   
    if(redNetInput != null) {
      redNetInput.onInputsChanged(worldObj, xCoord+out.offsetX, yCoord+out.offsetY, zCoord+out.offsetZ, out.getOpposite(), getOutputValues());
    }

    ticksSinceLastUpdate = 0;
  }

  public CircuitType getChannelCircuitType(int channel) {
    if(channel < 0 || channel >= numChannels) { return CircuitType.DISABLED; }
    return channelCircuitTypes[channel];
  }

  public CoordTriplet getMappedCoord(int channel) {
    return this.coordMappings[channel];
  }
 
  public boolean isInputActivatedOnPulse(int channel) {
    return this.inputActivatesOnPulse[channel];
  }

  // RedNet helper methods
  protected void clearChannel(int channel) {
    channelCircuitTypes[channel] = CircuitType.DISABLED;
    coordMappings[channel] = null;
    inputActivatesOnPulse[channel] = false;
    oldValue[channel] = 0;
  }

  protected TileEntity getMappedTileEntity(int channel) {
    if(channel < 0 || channel >= numChannels) { return null; }
    if(coordMappings[channel] == null) { return null; }
   
    CoordTriplet coord = coordMappings[channel];
   
    if(coord == null) { return null; }
    if(!this.worldObj.checkChunksExist(coord.x, coord.y, coord.z, coord.x, coord.y, coord.z)) {
      return null;
    }
   
    return this.worldObj.getTileEntity(coord.x, coord.y, coord.z);
  }
 
  protected void setControlRodInsertion(int channel, CoordTriplet coordTriplet, int newValue) {
    if(!this.isConnected()) { return; }
    if(!this.worldObj.checkChunksExist(coordTriplet.x, coordTriplet.y, coordTriplet.z,
                      coordTriplet.x, coordTriplet.y, coordTriplet.z)) {
      return;
    }
   
    TileEntity te = this.worldObj.getTileEntity(coordTriplet.x, coordTriplet.y, coordTriplet.z);
    if(te instanceof TileEntityReactorControlRod) {
      ((TileEntityReactorControlRod)te).setControlRodInsertion((short)newValue);
    }
    else {
      clearChannel(channel);
    }
  }
 
  protected NBTTagCompound encodeSetting(int channel) {
    NBTTagCompound entry = new NBTTagCompound();
   
    entry.setInteger("channel", channel);
    entry.setInteger("setting", this.channelCircuitTypes[channel].ordinal());
    if(isInput(this.channelCircuitTypes[channel]) && CircuitType.canBeToggledBetweenPulseAndNormal(this.channelCircuitTypes[channel])) {
      entry.setBoolean("pulse", this.inputActivatesOnPulse[channel]);
    }
    if( CircuitType.hasCoordinate(this.channelCircuitTypes[channel]) ) {
      CoordTriplet coord = this.coordMappings[channel];
      if(coord != null) {
        entry.setInteger("x", coord.x);
        entry.setInteger("y", coord.y);
        entry.setInteger("z", coord.z);
      }
    }
   
    return entry;
  }

  protected void decodeSetting(NBTTagCompound settingTag) {
    int channel = settingTag.getInteger("channel");
    int settingIdx = settingTag.getInteger("setting");
   
    clearChannel(channel);
   
    channelCircuitTypes[channel] = CircuitType.values()[settingIdx];
   
    if(isInput(this.channelCircuitTypes[channel]) && CircuitType.canBeToggledBetweenPulseAndNormal(this.channelCircuitTypes[channel])) {
      inputActivatesOnPulse[channel] = settingTag.getBoolean("pulse");
    }

    if( CircuitType.hasCoordinate(channelCircuitTypes[channel]) ) {
      if(settingTag.hasKey("x")) {
        int x, y, z;
        x = settingTag.getInteger("x");
        y = settingTag.getInteger("y");
        z = settingTag.getInteger("z");
        coordMappings[channel] = new CoordTriplet(x, y, z);
      }
    }
  }

  // Receives settings from a client via an update packet
  public void onCircuitUpdate(RedNetChange[] changes) {
    if(changes == null || changes.length < 1) { return; }
   
    for(int i = 0; i < changes.length; i++) {
      int channelID = changes[i].getChannel();
      CircuitType newType = changes[i].getType();
     
      channelCircuitTypes[channelID] = newType;
     
      if(CircuitType.canBeToggledBetweenPulseAndNormal(newType)) {
        inputActivatesOnPulse[channelID] = changes[i].getPulseOrToggle();
      }
     
      if(CircuitType.hasCoordinate(newType)) {
        CoordTriplet coord = changes[i].getCoord();
       
        // Validate that we're pointing at the right thing, just in case.
        if(coord != null) {
          TileEntity te = worldObj.getTileEntity(coord.x, coord.y, coord.z);
          if(!(te instanceof TileEntityReactorControlRod)) {
            BRLog.warning("Invalid tile entity reference at coordinate %s - rednet circuit expected a control rod", coord);
            coord = null;
          }
        }

        coordMappings[channelID] = coord;
      }
      else {
        coordMappings[channelID] = null;
      }
    }
   
    worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
    markDirty();
  }
 
  // Helpers
  protected void encodeSettings(NBTTagCompound destination) {
    NBTTagList tagArray = new NBTTagList();
   
    for(int i = 0; i < numChannels; i++) {
      tagArray.appendTag(encodeSetting(i));
    }
   
    destination.setTag("redNetConfig", tagArray);
  }
 
  protected void decodeSettings(NBTTagCompound source) {
    NBTTagList tagArray = source.getTagList("redNetConfig", 10);
    for(int i = 0; i < tagArray.tagCount(); i++) {
      decodeSetting( (NBTTagCompound)tagArray.getCompoundTagAt(i) );
    }
  }
 
  /**
   * Check for a world connection, if we're assembled.
   * @param world
   * @param x
   * @param y
   * @param z
   */
  protected void checkForConnections(IBlockAccess world, int x, int y, int z) {
    ForgeDirection out = getOutwardsDir();

    if(out == ForgeDirection.UNKNOWN) {
      redNetwork = null;
      redNetInput = null;
    }
    else {
      // Check for rednet connections nearby
      redNetwork = null;
      redNetInput = null;

      Block b = worldObj.getBlock(x + out.offsetX, y + out.offsetY, z + out.offsetZ);
      if(!(b instanceof BlockReactorPart)) {
        if(b instanceof IRedNetNetworkContainer) {
          redNetwork = (IRedNetNetworkContainer)b;
        }
        else if(b instanceof IRedNetInputNode) {
          redNetInput = (IRedNetInputNode)b;
        }
      }
    }
  }

  // Static Helpers
  public static boolean isInput(CircuitType type) { return type.ordinal() >= minInputEnumValue && type.ordinal() <= maxInputEnumValue; }
  public static boolean isOutput(CircuitType type) { return type.ordinal() >= minOutputEnumValue && type.ordinal() <= maxOutputEnumValue; }
}
TOP

Related Classes of erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorRedNetPort

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.