Package buildcraft.transport

Source Code of buildcraft.transport.PipeTransportPower

/**
* Copyright (c) 2011-2014, SpaceToad and the BuildCraft Team
* http://www.mod-buildcraft.com
*
* BuildCraft is distributed under the terms of the Minecraft Mod Public
* License 1.0, or MMPL. Please check the contents of the license located in
* http://www.mod-buildcraft.com/MMPL-1.0.txt
*/
package buildcraft.transport;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;
import cofh.api.energy.IEnergyConnection;
import cofh.api.energy.IEnergyHandler;
import buildcraft.BuildCraftCore;
import buildcraft.BuildCraftTransport;
import buildcraft.api.core.SafeTimeTracker;
import buildcraft.api.power.IPowerEmitter;
import buildcraft.api.power.IPowerReceptor;
import buildcraft.api.power.PowerHandler.PowerReceiver;
import buildcraft.api.power.PowerHandler.Type;
import buildcraft.api.transport.IPipeTile.PipeType;
import buildcraft.core.DefaultProps;
import buildcraft.transport.network.PacketPowerUpdate;
import buildcraft.transport.pipes.PipePowerCobblestone;
import buildcraft.transport.pipes.PipePowerDiamond;
import buildcraft.transport.pipes.PipePowerEmerald;
import buildcraft.transport.pipes.PipePowerGold;
import buildcraft.transport.pipes.PipePowerIron;
import buildcraft.transport.pipes.PipePowerQuartz;
import buildcraft.transport.pipes.PipePowerStone;
import buildcraft.transport.pipes.PipePowerWood;

public class PipeTransportPower extends PipeTransport {

  public static final Map<Class<? extends Pipe<?>>, Integer> powerCapacities = new HashMap<Class<? extends Pipe<?>>, Integer>();

  private static final int DISPLAY_SMOOTHING = 10;
  private static final int OVERLOAD_TICKS = 60;

  public short[] displayPower = new short[6];
  public int overload;
  public int[] nextPowerQuery = new int[6];
  public int[] internalNextPower = new int[6];
  public int maxPower = 80;
  public float[] movementStage = new float[] {0, 0, 0};

  private boolean needsInit = true;
  private TileEntity[] tiles = new TileEntity[6];

  private short[] prevDisplayPower = new short[6];

  private int[] powerQuery = new int[6];

  private long currentDate;
  private int[] internalPower = new int[6];
  private int[] externalPower = new int[6];

  private int highestPower;
  private SafeTimeTracker tracker = new SafeTimeTracker(2 * BuildCraftCore.updateFactor);

  public PipeTransportPower() {
    for (int i = 0; i < 6; ++i) {
      powerQuery[i] = 0;
    }

    for (int i = 0; i < 3; ++i) {
      movementStage[i] = (float) Math.random();
    }
  }

  @Override
  public PipeType getPipeType() {
    return PipeType.POWER;
  }

  public void initFromPipe(Class<? extends Pipe> pipeClass) {
    maxPower = powerCapacities.get(pipeClass);
  }

  @Override
  public boolean canPipeConnect(TileEntity tile, ForgeDirection side) {
    if (tile instanceof TileGenericPipe) {
      Pipe<?> pipe2 = ((TileGenericPipe) tile).pipe;
      if (BlockGenericPipe.isValid(pipe2) && !(pipe2.transport instanceof PipeTransportPower)) {
        return false;
      }
      return true;
    }

    if (tile instanceof IPowerReceptor) {
      IPowerReceptor receptor = (IPowerReceptor) tile;
      PowerReceiver receiver = receptor.getPowerReceiver(side.getOpposite());
      if (receiver != null && receiver.getType().canReceiveFromPipes()) {
        return true;
      }
    }

    if (tile instanceof IEnergyConnection) {
      IEnergyConnection handler = (IEnergyConnection) tile;
      if (handler != null && handler.canConnectEnergy(side.getOpposite())) {
        return true;
      }
    }

    if (container.pipe instanceof PipePowerWood && tile instanceof IPowerEmitter) {
      IPowerEmitter emitter = (IPowerEmitter) tile;
      if (emitter.canEmitPowerFrom(side.getOpposite())) {
        return true;
      }
    }

    return false;
  }

  @Override
  public void onNeighborBlockChange(int blockId) {
    super.onNeighborBlockChange(blockId);
        for (ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) {
            updateTile(side);
        }
  }

    private void updateTile(ForgeDirection side) {
        TileEntity tile = container.getTile(side);
        if (tile != null && container.isPipeConnected(side)) {
            tiles[side.ordinal()] = tile;
        } else {
            tiles[side.ordinal()] = null;
            internalPower[side.ordinal()] = 0;
            internalNextPower[side.ordinal()] = 0;
            displayPower[side.ordinal()] = 0;
        }
    }

  private void init() {
    if (needsInit) {
      needsInit = false;
            for (ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) {
                updateTile(side);
            }
    }
  }

  @Override
  public void updateEntity() {
    if (container.getWorldObj().isRemote) {
      // updating movement stage. We're only carrying the movement on half
      // the things. This is purely for animation purpose.

      for (int i = 0; i < 6; i += 2) {
        movementStage [i / 2] = (movementStage [i / 2] + 0.01F) % 1.0F;
      }

      return;
    }

    step();

    init();

        for (ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) {
            if (tiles[side.ordinal()] != null && tiles[side.ordinal()].isInvalid()) {
                updateTile(side);
            }
        }

    // Send the power to nearby pipes who requested it

    System.arraycopy(displayPower, 0, prevDisplayPower, 0, 6);
    Arrays.fill(displayPower, (short) 0);

    // STEP 1 - computes the total amount of power contained and total
    // amount of power queried

    int totalPowerContained = 0;
    int totalPowerQuery = 0;

    for (int dir = 0; dir < 6; ++dir) {
      totalPowerContained += internalPower[dir];
      if (internalPower[dir] == 0) {
        totalPowerQuery += powerQuery[dir];
      }
    }

    // STEP 2 - sends the power to all directions and computes the actual
    // amount of power that was consumed

    int totalPowerConsumed = 0;

    if (totalPowerContained > 0) {
      for (int out = 0; out < 6; ++out) {
        externalPower[out] = 0;

        if (powerQuery[out] > 0 && internalPower[out] == 0) {
          int powerConsumed = powerQuery[out] * totalPowerContained / totalPowerQuery;
          boolean tilePowered = false;

          if (tiles[out] instanceof TileGenericPipe) {
            // Transmit power to the nearby pipe

            TileGenericPipe nearbyTile = (TileGenericPipe) tiles[out];
            PipeTransportPower nearbyTransport = (PipeTransportPower) nearbyTile.pipe.transport;
            powerConsumed = nearbyTransport.receiveEnergy(
                ForgeDirection.VALID_DIRECTIONS[out].getOpposite(),
                powerConsumed);
            tilePowered = true;
          } else if (tiles[out] instanceof IEnergyHandler) {
            IEnergyHandler handler = (IEnergyHandler) tiles[out];

            if (handler.canConnectEnergy(ForgeDirection.VALID_DIRECTIONS[out].getOpposite())) {
              // Transmit power to an RF energy handler

              powerConsumed = handler.receiveEnergy(ForgeDirection.VALID_DIRECTIONS[out].getOpposite(),
                  powerConsumed, false);
              tilePowered = true;
            }
          } else {
            PowerReceiver prov = getReceiverOnSide(ForgeDirection.VALID_DIRECTIONS[out]);

            if (prov != null) {
              // Transmit power to the legacy power framework

              powerConsumed = (int) Math.ceil(prov.receiveEnergy(Type.PIPE, powerConsumed / 10.0,
                  ForgeDirection.VALID_DIRECTIONS[out].getOpposite()) * 10);
              tilePowered = true;
            }
          }

          if (!tilePowered) {
            externalPower[out] = powerConsumed;
          }

          displayPower[out] += powerConsumed;
          totalPowerConsumed += powerConsumed;
        }
      }
    }

    // STEP 3 - assume equal repartition of all consumed locations and
    // compute display for each source of power

    if (totalPowerConsumed > 0) {
      for (int in = 0; in < 6; ++in) {
        int powerConsumed = internalPower[in] * totalPowerConsumed / totalPowerContained;
        displayPower[in] += powerConsumed;
      }
    }

    // NEXT STEPS... other things to do...

    highestPower = 0;
    for (int i = 0; i < 6; i++) {
      displayPower[i] = (short) ((prevDisplayPower[i] * (DISPLAY_SMOOTHING - 1.0F) + displayPower[i]) / DISPLAY_SMOOTHING);

      if (displayPower[i] > highestPower) {
        highestPower = displayPower[i];
      }

      if (displayPower[i] < 0) {
        displayPower[i] = 0;
      }
    }

    overload += highestPower > maxPower * 0.95 ? 1 : -1;
    if (overload < 0) {
      overload = 0;
    }
    if (overload > OVERLOAD_TICKS) {
      overload = OVERLOAD_TICKS;
    }

    // Compute the tiles requesting energy that are not power pipes

    for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
        if (!outputOpen(dir)) {
          continue;
      }

      TileEntity tile = tiles [dir.ordinal()];
     
        if (tile instanceof TileGenericPipe && ((TileGenericPipe) tile).pipe.transport instanceof PipeTransportPower) {
          continue;
        }
       
      if (tile instanceof IEnergyHandler) {
        IEnergyHandler handler = (IEnergyHandler) tile;
        if (handler.canConnectEnergy(dir.getOpposite())) {
          int request = handler.receiveEnergy(dir.getOpposite(), this.maxPower, true);

          if (request > 0) {
            requestEnergy(dir, request);
          }
        }
      } else {
        PowerReceiver prov = getReceiverOnSide(dir);
        if (prov != null) {
          int request = (int) Math.floor(prov.powerRequest() * 10);

          if (request > 0) {
            requestEnergy(dir, request);
          }
        }
      }
    }

    // Sum the amount of energy requested on each side

    int[] transferQuery = new int[6];

    for (int i = 0; i < 6; ++i) {
      transferQuery[i] = 0;

      if (!inputOpen(ForgeDirection.getOrientation(i))) {
          continue;
      }

      for (int j = 0; j < 6; ++j) {
        if (j != i) {
          transferQuery[i] += powerQuery[j];
        }
      }

      transferQuery[i] = Math.min(transferQuery[i], maxPower);
    }

    // Transfer the requested energy to nearby pipes

    for (int i = 0; i < 6; ++i) {
      if (transferQuery[i] != 0) {
        if (tiles[i] != null) {
          TileEntity entity = tiles[i];

          if (entity instanceof TileGenericPipe) {
            TileGenericPipe nearbyTile = (TileGenericPipe) entity;

            if (nearbyTile.pipe == null) {
              continue;
            }

            PipeTransportPower nearbyTransport = (PipeTransportPower) nearbyTile.pipe.transport;
            nearbyTransport.requestEnergy(ForgeDirection.VALID_DIRECTIONS[i].getOpposite(), transferQuery[i]);
          }
        }
      }
    }

    if (tracker.markTimeIfDelay(container.getWorldObj())) {
      PacketPowerUpdate packet = new PacketPowerUpdate(container.xCoord, container.yCoord, container.zCoord);

      packet.displayPower = displayPower;
      packet.overload = isOverloaded();
      BuildCraftTransport.instance.sendToPlayers(packet, container.getWorldObj(), container.xCoord, container.yCoord, container.zCoord, DefaultProps.PIPE_CONTENTS_RENDER_DIST);
    }
  }

  private PowerReceiver getReceiverOnSide(ForgeDirection side) {
    TileEntity tile = tiles[side.ordinal()];
    if (!(tile instanceof IPowerReceptor)) {
      return null;
    }
    IPowerReceptor receptor = (IPowerReceptor) tile;
    PowerReceiver receiver = receptor.getPowerReceiver(side.getOpposite());
    if (receiver == null) {
      return null;
    }
    if (!receiver.getType().canReceiveFromPipes()) {
      return null;
    }
    return receiver;
  }

  public boolean isOverloaded() {
    return overload >= OVERLOAD_TICKS;
  }

  private void step() {
    if (container != null && container.getWorldObj() != null
        && currentDate != container.getWorldObj().getTotalWorldTime()) {
      currentDate = container.getWorldObj().getTotalWorldTime();

      powerQuery = nextPowerQuery;
      nextPowerQuery = new int[6];

      internalPower = internalNextPower;
      internalNextPower = new int[6];

      for (int i = 0; i < internalNextPower.length; ++i) {
        internalNextPower[i] = 0;
        nextPowerQuery[i] = 0;
      }
    }
  }

  /**
   * Do NOT ever call this from outside Buildcraft. It is NOT part of the API.
   * All power input MUST go through designated input pipes, such as Wooden
   * Power Pipes or a subclass thereof.
   */
  public int receiveEnergy(ForgeDirection from, int valI) {
    int val = valI;
    step();
    if (this.container.pipe instanceof IPipeTransportPowerHook) {
      int ret = ((IPipeTransportPowerHook) this.container.pipe).receiveEnergy(from, val);
      if (ret >= 0) {
        return ret;
      }
    }
    int side = from.ordinal();
    if (internalNextPower[side] > maxPower) {
      return 0;
    }

    internalNextPower[side] += val;

    if (internalNextPower[side] > maxPower) {
      val -= internalNextPower[side] - maxPower;
      internalNextPower[side] = maxPower;
      if (val < 0) {
        val = 0;
      }
    }

    return val;
  }

  public void requestEnergy(ForgeDirection from, int amount) {
    step();
   
    if (this.container.pipe instanceof IPipeTransportPowerHook) {
        nextPowerQuery[from.ordinal()] += ((IPipeTransportPowerHook) this.container.pipe).requestEnergy(from, amount);
    } else {
        nextPowerQuery[from.ordinal()] += amount;
    }
  }

  @Override
  public void initialize() {
    currentDate = container.getWorldObj().getTotalWorldTime();
  }

  @Override
  public void readFromNBT(NBTTagCompound nbttagcompound) {
    super.readFromNBT(nbttagcompound);

    for (int i = 0; i < 6; ++i) {
      powerQuery[i] = nbttagcompound.getInteger("powerQuery[" + i + "]");
      nextPowerQuery[i] = nbttagcompound.getInteger("nextPowerQuery[" + i + "]");
      internalPower[i] = nbttagcompound.getInteger("internalPower[" + i + "]");
      internalNextPower[i] = nbttagcompound.getInteger("internalNextPower[" + i + "]");
    }

  }

  @Override
  public void writeToNBT(NBTTagCompound nbttagcompound) {
    super.writeToNBT(nbttagcompound);

    for (int i = 0; i < 6; ++i) {
      nbttagcompound.setInteger("powerQuery[" + i + "]", powerQuery[i]);
      nbttagcompound.setInteger("nextPowerQuery[" + i + "]", nextPowerQuery[i]);
      nbttagcompound.setInteger("internalPower[" + i + "]", internalPower[i]);
      nbttagcompound.setInteger("internalNextPower[" + i + "]", internalNextPower[i]);
    }
  }

  /**
   * Client-side handler for receiving power updates from the server;
   *
   * @param packetPower
   */
  public void handlePowerPacket(PacketPowerUpdate packetPower) {
    displayPower = packetPower.displayPower;
    overload = packetPower.overload ? OVERLOAD_TICKS : 0;
  }

  /**
   * This can be use to provide a rough estimate of how much power is flowing
   * through a pipe. Measured in RF/t.
   *
   * @return RF/t
   */
  public int getCurrentPowerTransferRate() {
    return highestPower;
  }

  /**
   * This can be use to provide a rough estimate of how much power is
   * contained in a pipe. Measured in RF.
   *
   * Max should be around (throughput * internalPower.length * 2), ie 112 MJ for a Cobblestone Pipe.
   *
   * @return RF
   */
  public int getCurrentPowerAmount() {
    int amount = 0;
    for (int d : internalPower) {
      amount += d;
    }
    for (int d : internalNextPower) {
      amount += d;
    }
    return amount;
  }

  public float getPistonStage(int i) {
    if (movementStage [i] < 0.5F) {
      return movementStage [i] * 2;
    } else {
      return 1 - (movementStage [i] - 0.5F) * 2;
    }
  }

  public int clearInstantPower() {
    int amount = 0;

    for (int i = 0; i < internalPower.length; ++i) {
      amount += internalPower [i];
      internalPower [i] = 0;
    }

    return amount;
  }

  public int consumePower(ForgeDirection dir, int max) {
    int result;

    if (externalPower[dir.ordinal()] < max) {
      result = externalPower[dir.ordinal()];
    } else {
      result = max;
      externalPower[dir.ordinal()] -= max;
    }

    return result;
  }

  public boolean isQueryingPower() {
    for (int d : powerQuery) {
      if (d > 0) {
        return true;
      }
    }

    return false;
  }

  static {
    powerCapacities.put(PipePowerCobblestone.class, 80);
    powerCapacities.put(PipePowerStone.class, 160);
    powerCapacities.put(PipePowerWood.class, 320);
    powerCapacities.put(PipePowerQuartz.class, 640);
    powerCapacities.put(PipePowerIron.class, 1280);
    powerCapacities.put(PipePowerGold.class, 2560);
    powerCapacities.put(PipePowerEmerald.class, 2560);
    powerCapacities.put(PipePowerDiamond.class, 10240);
  }
}
TOP

Related Classes of buildcraft.transport.PipeTransportPower

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.