568 lines
14 KiB
Java
568 lines
14 KiB
Java
/**
|
|
* Copyright (c) 2011-2017, SpaceToad and the BuildCraft Team
|
|
* http://www.mod-buildcraft.com
|
|
* <p/>
|
|
* 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.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.Random;
|
|
|
|
import net.minecraft.entity.Entity;
|
|
import net.minecraft.entity.EntityLivingBase;
|
|
import net.minecraft.entity.player.EntityPlayer;
|
|
import net.minecraft.item.Item;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.nbt.NBTTagCompound;
|
|
import net.minecraft.tileentity.TileEntity;
|
|
import net.minecraft.world.World;
|
|
|
|
import cpw.mods.fml.relauncher.Side;
|
|
import cpw.mods.fml.relauncher.SideOnly;
|
|
import net.minecraftforge.common.util.ForgeDirection;
|
|
|
|
import buildcraft.BuildCraftTransport;
|
|
import buildcraft.api.core.IIconProvider;
|
|
import buildcraft.api.gates.IGate;
|
|
import buildcraft.api.statements.ActionState;
|
|
import buildcraft.api.statements.IActionInternal;
|
|
import buildcraft.api.statements.StatementSlot;
|
|
import buildcraft.api.transport.IPipe;
|
|
import buildcraft.api.transport.IPipeTile;
|
|
import buildcraft.api.transport.PipeWire;
|
|
import buildcraft.core.internal.IDropControlInventory;
|
|
import buildcraft.core.lib.inventory.InvUtils;
|
|
import buildcraft.core.lib.utils.Utils;
|
|
import buildcraft.transport.gates.GateFactory;
|
|
import buildcraft.transport.statements.ActionValve.ValveState;
|
|
|
|
public abstract class Pipe<T extends PipeTransport> implements IDropControlInventory, IPipe {
|
|
public int[] wireSignalStrength = new int[]{0, 0, 0, 0};
|
|
public boolean[] wireSet = new boolean[]{false, false, false, false};
|
|
|
|
public TileGenericPipe container;
|
|
public final T transport;
|
|
public final Item item;
|
|
public final Gate[] gates = new Gate[ForgeDirection.VALID_DIRECTIONS.length];
|
|
public PipeEventBus eventBus = new PipeEventBus();
|
|
|
|
private boolean initialized = false;
|
|
private boolean scheduleWireUpdate;
|
|
|
|
private ArrayList<ActionState> actionStates = new ArrayList<ActionState>();
|
|
|
|
public Pipe(T transport, Item item) {
|
|
this.transport = transport;
|
|
this.item = item;
|
|
|
|
eventBus.registerHandler(this);
|
|
}
|
|
|
|
public void setTile(TileEntity tile) {
|
|
this.container = (TileGenericPipe) tile;
|
|
transport.setTile((TileGenericPipe) tile);
|
|
}
|
|
|
|
public void resolveActions() {
|
|
for (Gate gate : gates) {
|
|
if (gate != null) {
|
|
gate.resolveActions();
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean blockActivated(EntityPlayer player, ForgeDirection side) {
|
|
return false;
|
|
}
|
|
|
|
public void onBlockPlaced() {
|
|
transport.onBlockPlaced();
|
|
}
|
|
|
|
public void onBlockPlacedBy(EntityLivingBase placer) {
|
|
}
|
|
|
|
public void onNeighborBlockChange(int blockId) {
|
|
for (ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) {
|
|
transport.onNeighborChange(d);
|
|
}
|
|
}
|
|
|
|
public boolean canPipeConnect(TileEntity tile, ForgeDirection side) {
|
|
Pipe<?> otherPipe;
|
|
|
|
if (tile instanceof IPipeTile) {
|
|
otherPipe = (Pipe<?>) ((IPipeTile) tile).getPipe();
|
|
if (!BlockGenericPipe.isFullyDefined(otherPipe)) {
|
|
return false;
|
|
}
|
|
|
|
if (!PipeConnectionBans.canPipesConnect(getClass(), otherPipe.getClass())) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return transport.canPipeConnect(tile, side);
|
|
}
|
|
|
|
/**
|
|
* Should return the textureindex used by the Pipe Item Renderer, as this is
|
|
* done client-side the default implementation might not work if your
|
|
* getTextureIndex(Orienations.Unknown) has logic. Then override this
|
|
*/
|
|
public int getIconIndexForItem() {
|
|
return getIconIndex(ForgeDirection.UNKNOWN);
|
|
}
|
|
|
|
/**
|
|
* Should return the IIconProvider that provides icons for this pipe
|
|
*
|
|
* @return An array of icons
|
|
*/
|
|
@SideOnly(Side.CLIENT)
|
|
public abstract IIconProvider getIconProvider();
|
|
|
|
/**
|
|
* Should return the index in the array returned by GetTextureIcons() for a
|
|
* specified direction
|
|
*
|
|
* @param direction - The direction for which the indexed should be
|
|
* rendered. Unknown for pipe center
|
|
*
|
|
* @return An index valid in the array returned by getTextureIcons()
|
|
*/
|
|
public abstract int getIconIndex(ForgeDirection direction);
|
|
|
|
public void updateEntity() {
|
|
transport.updateEntity();
|
|
|
|
actionStates.clear();
|
|
|
|
// Update the gate if we have any
|
|
if (!container.getWorldObj().isRemote) {
|
|
for (Gate gate : gates) {
|
|
if (gate != null) {
|
|
gate.resolveActions();
|
|
gate.tick();
|
|
}
|
|
}
|
|
|
|
if (scheduleWireUpdate) {
|
|
updateSignalState();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void writeToNBT(NBTTagCompound data) {
|
|
transport.writeToNBT(data);
|
|
|
|
// Save gate if any
|
|
for (int i = 0; i < ForgeDirection.VALID_DIRECTIONS.length; i++) {
|
|
final String key = "Gate[" + i + "]";
|
|
Gate gate = gates[i];
|
|
if (gate != null) {
|
|
NBTTagCompound gateNBT = new NBTTagCompound();
|
|
gate.writeToNBT(gateNBT);
|
|
data.setTag(key, gateNBT);
|
|
} else {
|
|
data.removeTag(key);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
data.setBoolean("wireSet[" + i + "]", wireSet[i]);
|
|
}
|
|
}
|
|
|
|
public void readFromNBT(NBTTagCompound data) {
|
|
transport.readFromNBT(data);
|
|
|
|
for (int i = 0; i < ForgeDirection.VALID_DIRECTIONS.length; i++) {
|
|
final String key = "Gate[" + i + "]";
|
|
gates[i] = data.hasKey(key) ? GateFactory.makeGate(this, data.getCompoundTag(key)) : null;
|
|
}
|
|
|
|
// Legacy support
|
|
if (data.hasKey("Gate")) {
|
|
transport.container.setGate(GateFactory.makeGate(this, data.getCompoundTag("Gate")), 0);
|
|
|
|
data.removeTag("Gate");
|
|
}
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
wireSet[i] = data.getBoolean("wireSet[" + i + "]");
|
|
}
|
|
}
|
|
|
|
public boolean isInitialized() {
|
|
return initialized;
|
|
}
|
|
|
|
public void initialize() {
|
|
transport.initialize();
|
|
updateSignalState();
|
|
initialized = true;
|
|
}
|
|
|
|
public void updateSignalState() {
|
|
for (PipeWire c : PipeWire.values()) {
|
|
if (wireSet[c.ordinal()]) {
|
|
updateSignalState(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void updateSignalState(PipeWire c) {
|
|
int prevStrength = wireSignalStrength[c.ordinal()];
|
|
boolean isBroadcast = false;
|
|
|
|
for (Gate g : gates) {
|
|
if (g != null && (g.broadcastSignal & (1 << c.ordinal())) != 0) {
|
|
isBroadcast = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (isBroadcast) {
|
|
if (prevStrength < 255) {
|
|
propagateSignalState(c, 255);
|
|
}
|
|
} else {
|
|
List<Pipe<?>> pipes = new ArrayList<Pipe<?>>();
|
|
int maxStrength = 0;
|
|
|
|
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
|
|
TileEntity tile = container.getTile(dir);
|
|
if (tile instanceof IPipeTile) {
|
|
Pipe<?> pipe = (Pipe<?>) ((IPipeTile) tile).getPipe();
|
|
if (isWireConnectedTo(tile, pipe, c, dir)) {
|
|
pipes.add(pipe);
|
|
int pipeStrength = pipe.wireSignalStrength[c.ordinal()];
|
|
if (pipeStrength > maxStrength) {
|
|
maxStrength = pipeStrength;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (maxStrength > prevStrength && maxStrength > 1) {
|
|
wireSignalStrength[c.ordinal()] = maxStrength - 1;
|
|
} else {
|
|
wireSignalStrength[c.ordinal()] = 0;
|
|
}
|
|
|
|
if (prevStrength != wireSignalStrength[c.ordinal()]) {
|
|
container.scheduleRenderUpdate();
|
|
}
|
|
|
|
if (wireSignalStrength[c.ordinal()] == 0) {
|
|
for (Pipe<?> p : pipes) {
|
|
if (p.wireSignalStrength[c.ordinal()] > 0) {
|
|
p.updateSignalState(c);
|
|
}
|
|
}
|
|
} else {
|
|
for (Pipe<?> p : pipes) {
|
|
if (p.wireSignalStrength[c.ordinal()] < (wireSignalStrength[c.ordinal()] - 1)) {
|
|
p.updateSignalState(c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void propagateSignalState(PipeWire c, int s) {
|
|
wireSignalStrength[c.ordinal()] = s;
|
|
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
|
|
TileEntity tile = container.getTile(dir);
|
|
if (tile instanceof IPipeTile) {
|
|
Pipe<?> pipe = (Pipe<?>) ((IPipeTile) tile).getPipe();
|
|
if (isWireConnectedTo(tile, pipe, c, dir)) {
|
|
if (s == 0) {
|
|
if (pipe.wireSignalStrength[c.ordinal()] > 0) {
|
|
pipe.updateSignalState(c);
|
|
}
|
|
} else {
|
|
if (pipe.wireSignalStrength[c.ordinal()] < s) {
|
|
pipe.updateSignalState(c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean inputOpen(ForgeDirection from) {
|
|
return transport.inputOpen(from);
|
|
}
|
|
|
|
public boolean outputOpen(ForgeDirection to) {
|
|
return transport.outputOpen(to);
|
|
}
|
|
|
|
public void onEntityCollidedWithBlock(Entity entity) {
|
|
}
|
|
|
|
public boolean canConnectRedstone() {
|
|
for (Gate gate : gates) {
|
|
if (gate != null) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public int getMaxRedstoneOutput(ForgeDirection dir) {
|
|
int output = 0;
|
|
|
|
for (ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) {
|
|
output = Math.max(output, getRedstoneOutput(side));
|
|
if (side == dir) {
|
|
output = Math.max(output, getRedstoneOutputSide(side));
|
|
}
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
private int getRedstoneOutput(ForgeDirection dir) {
|
|
Gate gate = gates[dir.ordinal()];
|
|
|
|
return gate != null ? gate.getRedstoneOutput() : 0;
|
|
}
|
|
|
|
private int getRedstoneOutputSide(ForgeDirection dir) {
|
|
Gate gate = gates[dir.ordinal()];
|
|
|
|
return gate != null ? gate.getSidedRedstoneOutput() : 0;
|
|
}
|
|
|
|
public int isPoweringTo(int side) {
|
|
ForgeDirection o = ForgeDirection.getOrientation(side).getOpposite();
|
|
|
|
TileEntity tile = container.getTile(o);
|
|
|
|
if (tile instanceof IPipeTile && container.isPipeConnected(o)) {
|
|
return 0;
|
|
} else {
|
|
return getMaxRedstoneOutput(o);
|
|
}
|
|
}
|
|
|
|
public int isIndirectlyPoweringTo(int l) {
|
|
return isPoweringTo(l);
|
|
}
|
|
|
|
public void randomDisplayTick(Random random) {
|
|
}
|
|
|
|
@Override
|
|
public boolean isWired(PipeWire color) {
|
|
return wireSet[color.ordinal()];
|
|
}
|
|
|
|
@Override
|
|
public boolean isWireActive(PipeWire color) {
|
|
return wireSignalStrength[color.ordinal()] > 0;
|
|
}
|
|
|
|
@Deprecated
|
|
public boolean hasGate() {
|
|
for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) {
|
|
if (hasGate(direction)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public boolean hasGate(ForgeDirection side) {
|
|
return container.hasGate(side);
|
|
}
|
|
|
|
protected void notifyBlocksOfNeighborChange(ForgeDirection side) {
|
|
container.getWorldObj().notifyBlocksOfNeighborChange(container.xCoord + side.offsetX, container.yCoord + side.offsetY, container.zCoord + side.offsetZ, BuildCraftTransport.genericPipeBlock);
|
|
}
|
|
|
|
protected void updateNeighbors(boolean needSelf) {
|
|
if (needSelf) {
|
|
container.getWorldObj().notifyBlocksOfNeighborChange(container.xCoord, container.yCoord, container.zCoord, BuildCraftTransport.genericPipeBlock);
|
|
}
|
|
for (ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) {
|
|
notifyBlocksOfNeighborChange(side);
|
|
}
|
|
}
|
|
|
|
public void dropItem(ItemStack stack) {
|
|
InvUtils.dropItems(container.getWorldObj(), stack, container.xCoord, container.yCoord, container.zCoord);
|
|
}
|
|
|
|
public ArrayList<ItemStack> computeItemDrop() {
|
|
ArrayList<ItemStack> result = new ArrayList<ItemStack>();
|
|
|
|
for (PipeWire pipeWire : PipeWire.VALUES) {
|
|
if (wireSet[pipeWire.ordinal()]) {
|
|
result.add(pipeWire.getStack());
|
|
}
|
|
}
|
|
|
|
for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) {
|
|
if (container.hasPipePluggable(direction)) {
|
|
Collections.addAll(result, container.getPipePluggable(direction).getDropItems(container));
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public LinkedList<IActionInternal> getActions() {
|
|
LinkedList<IActionInternal> result = new LinkedList<IActionInternal>();
|
|
|
|
for (ValveState state : ValveState.VALUES) {
|
|
result.add(BuildCraftTransport.actionValve[state.ordinal()]);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public void resetGates() {
|
|
for (int i = 0; i < gates.length; i++) {
|
|
Gate gate = gates[i];
|
|
if (gate != null) {
|
|
gate.resetGate();
|
|
}
|
|
gates[i] = null;
|
|
}
|
|
|
|
scheduleWireUpdate = true;
|
|
container.scheduleRenderUpdate();
|
|
}
|
|
|
|
protected void actionsActivated(Collection<StatementSlot> actions) {
|
|
}
|
|
|
|
public TileGenericPipe getContainer() {
|
|
return container;
|
|
}
|
|
|
|
public boolean isWireConnectedTo(TileEntity tile, PipeWire color, ForgeDirection direction) {
|
|
if (!(tile instanceof IPipeTile)) {
|
|
return false;
|
|
}
|
|
|
|
return isWireConnectedTo(tile, (Pipe) (((IPipeTile) tile).getPipe()), color, direction);
|
|
}
|
|
|
|
public boolean isWireConnectedTo(TileEntity tile, Pipe pipe, PipeWire color, ForgeDirection dir) {
|
|
if (!BlockGenericPipe.isFullyDefined(pipe)) {
|
|
return false;
|
|
}
|
|
|
|
if (!pipe.wireSet[color.ordinal()]) {
|
|
return false;
|
|
}
|
|
|
|
if (container.hasBlockingPluggable(dir) || pipe.container.hasBlockingPluggable(dir.getOpposite())) {
|
|
return false;
|
|
}
|
|
|
|
return pipe.transport instanceof PipeTransportStructure || transport instanceof PipeTransportStructure
|
|
|| Utils.checkPipesConnections(
|
|
container, tile);
|
|
}
|
|
|
|
public void dropContents() {
|
|
transport.dropContents();
|
|
}
|
|
|
|
public List<ItemStack> getDroppedItems() {
|
|
return transport.getDroppedItems();
|
|
}
|
|
|
|
/**
|
|
* If this pipe is open on one side, return it.
|
|
*/
|
|
public ForgeDirection getOpenOrientation() {
|
|
int connectionsNum = 0;
|
|
|
|
ForgeDirection targetOrientation = ForgeDirection.UNKNOWN;
|
|
|
|
for (ForgeDirection o : ForgeDirection.VALID_DIRECTIONS) {
|
|
if (container.isPipeConnected(o)) {
|
|
|
|
connectionsNum++;
|
|
|
|
if (connectionsNum == 1) {
|
|
targetOrientation = o;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (connectionsNum > 1 || connectionsNum == 0) {
|
|
return ForgeDirection.UNKNOWN;
|
|
}
|
|
|
|
return targetOrientation.getOpposite();
|
|
}
|
|
|
|
@Override
|
|
public boolean doDrop() {
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Called when TileGenericPipe.invalidate() is called
|
|
*/
|
|
public void invalidate() {
|
|
}
|
|
|
|
/**
|
|
* Called when TileGenericPipe.validate() is called
|
|
*/
|
|
public void validate() {
|
|
}
|
|
|
|
/**
|
|
* Called when TileGenericPipe.onChunkUnload is called
|
|
*/
|
|
public void onChunkUnload() {
|
|
}
|
|
|
|
public World getWorld() {
|
|
return container.getWorldObj();
|
|
}
|
|
|
|
@Override
|
|
public IPipeTile getTile() {
|
|
return container;
|
|
}
|
|
|
|
@Override
|
|
public IGate getGate(ForgeDirection side) {
|
|
if (side == ForgeDirection.UNKNOWN) {
|
|
return null;
|
|
}
|
|
|
|
return gates[side.ordinal()];
|
|
}
|
|
|
|
private void pushActionState(ActionState state) {
|
|
actionStates.add(state);
|
|
}
|
|
|
|
private Collection<ActionState> getActionStates() {
|
|
return actionStates;
|
|
}
|
|
|
|
public void scheduleWireUpdate() {
|
|
scheduleWireUpdate = true;
|
|
}
|
|
}
|