/* * Copyright (c) CovertJaguar, 2014 http://railcraft.info * * This code is the property of CovertJaguar * and may only be used with explicit written * permission unless otherwise specified on the * license page at http://railcraft.info/wiki/info:license. */ package mods.railcraft.common.blocks.signals; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.HashSet; import java.util.Set; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import mods.railcraft.api.signals.SignalAspect; import mods.railcraft.common.plugins.forge.PowerPlugin; import mods.railcraft.common.plugins.forge.WorldPlugin; import mods.railcraft.common.util.misc.MiscTools; import net.minecraft.block.Block; import net.minecraft.block.BlockDirectional; import net.minecraft.init.Blocks; import net.minecraftforge.common.util.ForgeDirection; import static net.minecraftforge.common.util.ForgeDirection.*; import static mods.railcraft.common.plugins.forge.PowerPlugin.*; public class TileBoxSequencer extends TileBoxBase { private static final int MAX_ITERATIONS = 64; private ForgeDirection sideOutput = ForgeDirection.NORTH; private boolean powerState = false; private boolean neighborState = false; public TileBoxSequencer() { } @Override public EnumSignal getSignalType() { return EnumSignal.BOX_SEQUENCER; } @Override public void onNeighborBlockChange(Block block) { super.onNeighborBlockChange(block); if (worldObj.isRemote) return; boolean p = PowerPlugin.isBlockBeingPoweredByRepeater(worldObj, xCoord, yCoord, zCoord); if (!powerState && p) { powerState = p; incrementSequencer(true, new HashSet<TileEntity>(), 0); } else powerState = p; } @Override public void onNeighborStateChange(TileBoxBase neighbor, ForgeDirection side) { if (worldObj.isRemote) return; if (neighbor instanceof TileBoxSequencer) return; if (neighbor instanceof TileBoxCapacitor) return; boolean p = neighbor.isEmittingRedstone(side); if (!neighborState && p) { neighborState = p; incrementSequencer(true, new HashSet<TileEntity>(), 0); } else neighborState = p; } private void incrementSequencer(boolean firstPass, Set<TileEntity> visitedFirstPass, int numberOfIterations) { if (firstPass) { visitedFirstPass.add(this); TileEntity tile = tileCache.getTileOnSide(sideOutput); if (tile instanceof TileBoxSequencer && !visitedFirstPass.contains(tile)) { TileBoxSequencer box = (TileBoxSequencer) tile; box.incrementSequencer(true, visitedFirstPass, numberOfIterations); return; } } ForgeDirection newSide = sideOutput.getRotation(UP); while (newSide != sideOutput && !canOutputToSide(newSide)) { newSide = newSide.getRotation(UP); } sideOutput = newSide; updateNeighbors(); if (numberOfIterations >= MAX_ITERATIONS) return; TileEntity tile = tileCache.getTileOnSide(sideOutput); if (tile instanceof TileBoxSequencer) { TileBoxSequencer box = (TileBoxSequencer) tile; box.incrementSequencer(false, visitedFirstPass, numberOfIterations + 1); } } private boolean canOutputToSide(ForgeDirection side) { TileEntity tile = tileCache.getTileOnSide(side); if (tile instanceof TileBoxSequencer) return true; if (tile instanceof TileBoxBase) return ((TileBoxBase) tile).canReceiveAspect(); Block block = WorldPlugin.getBlockOnSide(worldObj, xCoord, yCoord, zCoord, side); if (block == Blocks.redstone_wire) return true; if (block == Blocks.unpowered_repeater || block == Blocks.powered_repeater) { int facing = BlockDirectional.getDirection(WorldPlugin.getBlockMetadataOnSide(worldObj, xCoord, yCoord, zCoord, side)); switch (side) { case NORTH: return facing == 0; case SOUTH: return facing == 2; case EAST: return facing == 1; case WEST: return facing == 3; } } return false; } private void updateNeighbors() { sendUpdateToClient(); notifyBlocksOfNeighborChange(); updateNeighborBoxes(); } @Override public int getPowerOutput(int side) { TileEntity tile = tileCache.getTileOnSide(MiscTools.getOppositeSide(side)); if (tile instanceof TileBoxBase) return NO_POWER; return sideOutput.getOpposite().ordinal() == side ? FULL_POWER : NO_POWER; } @Override public boolean isEmittingRedstone(ForgeDirection side) { return sideOutput == side; } @Override public SignalAspect getBoxSignalAspect(ForgeDirection side) { return sideOutput == side ? SignalAspect.GREEN : SignalAspect.RED; } @Override public void writeToNBT(NBTTagCompound data) { super.writeToNBT(data); data.setByte("sideOutput", (byte) sideOutput.ordinal()); data.setBoolean("powerState", powerState); data.setBoolean("neighborState", neighborState); } @Override public void readFromNBT(NBTTagCompound data) { super.readFromNBT(data); sideOutput = ForgeDirection.getOrientation(data.getByte("sideOutput")); powerState = data.getBoolean("powerState"); neighborState = data.getBoolean("neighborState"); } @Override public void writePacketData(DataOutputStream data) throws IOException { super.writePacketData(data); data.writeByte(sideOutput.ordinal()); } @Override public void readPacketData(DataInputStream data) throws IOException { super.readPacketData(data); sideOutput = ForgeDirection.getOrientation(data.readByte()); markBlockForUpdate(); } @Override public boolean isConnected(ForgeDirection side) { TileEntity tile = tileCache.getTileOnSide(side); if (tile instanceof TileBoxSequencer) return true; if (tile instanceof TileBoxBase) return ((TileBoxBase) tile).canReceiveAspect() || ((TileBoxBase) tile).canTransferAspect(); return false; } @Override public boolean canTransferAspect() { return true; } @Override public boolean canReceiveAspect() { return true; } }